How can I use scss files and fonts in Vue project - javascript

I created new project with vue-cli and I want to use global scss files in my projects to apply global styles. Also I want to use font-families without importing scss file in every component where I want to use it
I found lots of solutions, but none of them help me. I'm new with webpack, so it is hard to understand what exactly goes wrong.
I install loader npm install sass-loader node-sass --save-dev and try to do lots of things with webpack
webpack.config.js
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
},
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
],
},
{
test: /\.sass$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader?indentedSyntax'
],
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this necessary.
'scss': [
'vue-style-loader',
'css-loader',
'sass-loader'
],
'sass': [
'vue-style-loader',
'css-loader',
'sass-loader?indentedSyntax'
]
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
src/assets/scss/fonts.scss
#font-face {
font-family: "SuisseIntl";
src: url("../fonts/SuisseIntl.woff") format("woff");
}
#font-face {
font-family: "SuisseIntl-Light";
src: url("../fonts/SuisseIntl-Light.woff") format("woff");
}
#font-face {
font-family: "SuisseIntl-SemiBold";
src: url("../fonts/SuisseIntl-SemiBold.woff") format("woff");
}
$body-bg: red;
I want to be able to use font families in style tag inside every component and I want to be able to import scss files to component like this#import '../assets/scss/fonts'; , but now this cause error.
Can someone help me, please? What should I do to make it work?

vue3 (no idea about vue2)
Late but I maybe still a help for someone.
I assume you have a working vue app already. I normaly create mine with vue ui or cli and use typescript. Many things are preconfigured then. Folder structure looks like this:
/node_modules
/public
/src
/assets
/components
/...
/tests
...
package.json
...
create a vue.config.js (if not exists) in the root (where package.json lies) and put this into it:
module.exports = {
css: {
loaderOptions: {
sass: {
// Or wherever your scss files are. I have a "style.scss" which imports all the others
// # in my case points to src/* and is defined in tsconfig.json. Substitute it with src should do fine
prependData: `
#import "#/assets/scss/style.scss";
`,
},
},
},
};
(optional) put your fonts into (if you want them deliver by yourself)
/assets/fonts/
load your fonts in the style.scss (example)
/* local path, dont forget that ~#/ in the url */
#font-face {
font-family : 'Raleway';
font-style : normal;
src : url('~#/assets/fonts/Raleway-VariableFont_wght.ttf') format('truetype-variations')
}
/* or from google fronts */
#import url(http://fonts.googleapis.com/css?family=Roboto+Slab|Open+Sans:400italic,700italic,400,700);
Double check the font path in the scss file. Vue looks into /src folder. So the rootpath for sass-compiler is inside the src folder and the font-url has to start with ~#/assets/fonts/

To use scss in components, make sure you have both sass-loader and node-sass installed as dev dependencies. This will allow you to use scss styling in components with:
<style lang="scss">
</style>
If you want to include some actual styling (something like your fonts that creates actual styling lines in css), create a scss file and include it in your top-most Vue file (by default something like App.vue).
#import "./some/relative/path/to/your/scss/file.scss";
If you want to include variables, functions or mixins in every component without explicitly having to define the import, make a scss file that serves as your entry point for such configuration, e.g. /scss/config.scss. Make sure that you do not output ANY css rules in this file, because these css rules would be duplicated many times for each component. Instead use the file I mentioned before and import your configuration in there as well.
Then, go to your vue.config.js file and add the following to the object:
css: {
loaderOptions: {
sass: {
data: `
#import "#/scss/config.scss";
`
}
}
}
This will automatically load the config file. If you are still using the old structure, you can get the same behaviour by adding a data option to your own sass-loader:
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
data: '#import "config";',
includePaths: [
path.join(__dirname, 'src/scss') // Or however else you get to your scss folder
]
}
}
],
},

Here is an example that works for me on the latest version of Vue-CLI (#vue/cli 5.0.0-rc.2, vue3) + TS + dart-sass:
I saved my fonts to the assets folder (src/assets/fonts/public-sans-vf.woff2);
Then I created the _fonts.css file in which I describe the rule for the font (src/assets/scss/_fonts.scss);
#font-face {
font-family: "Public Sans";
src: url("~#/assets/fonts/public-sans-vf.woff2")
format("woff2 supports variations"),
url("~#/assets/fonts/public-sans-vf.woff2") format("woff2-variations");
font-style: normal;
font-weight: 400;
font-display: swap;
}
And then I configure the fonts in vue.config.ts
const { defineConfig } = require('#vue/cli-service');
module.exports = defineConfig({
transpileDependencies: true,
css: {
loaderOptions: {
scss: {
additionalData: `
#import "#/assets/scss/_variables.scss";
#import "#/assets/scss/_fonts.scss";
`,
},
},
},
});

Related

Including an image in imported css file in react using webpack

Ok, so I've been reading article after article after article and have not found a good solution to this, what should be a very simple process in developing a web app...
I have my setup for webpack, babel, react and in my react app, I have a very basic css import. I've imported the image, which lives in src/static/assets/images/bg.png and I can embed it using inline css in my react component without troubles. However, I want to include my image from an included css file. The css file is parsed, but then I get the error 'Module build failed' and Can't resolve './bg.png' or a very similar path error when I mess around with the path inside the included css. I have file-loader, and url-loader installed and the file is moved into the dist/ folder route (though honestly, I would rather have an images/ folder in the dist where this goes, but that's another task.
So the quest: what needs to change to have the image included from the css. I've read https://create-react-app.dev/docs/adding-images-fonts-and-files/ and that alludes that my code should work, yet it doesn't.
Code is below, or from my repo if you want the whole code base: https://github.com/abendago/reactimages
REACT Code
import React from "react";
import './css/style.css'
import bg from './static/assets/images/bg.png'
function App() {
return (
<h1 style={{backgroundImage: "url(" + bg + ")"}}>In THe App Here</h1>
);
}
export default App;
src/css/style.css
body { background-image: url(./bg.png)}
webpack config
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
},
],
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin()
],
devServer: {
contentBase: path.join(__dirname, 'public')
}
};
You have to set the relative path with your image to solve your issue since current your path doesn't relate to anything:
body { background-image: url('../static/assets/images/bg.png')}
You might want to install file loader and image-webpack-loader and update your webpack config to reflect the following.
{
test: /\.(png|gif|jpe?g)$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
mozjpege: {
progressive: true,
quality: 80,
},
optipng: {
enabled: false,
},
pngquant:{
quality: '65-90',
speed: 4,
},
}
}
]
}
Although I think your image doesn't load when referenced in css, because you don't have a quote around it. Replace body { background-image: url(./bg.png)} with body { background-image: URL('./bg.png')} - https://developer.mozilla.org/en-US/docs/Web/CSS/background-image

Stop extract-css-chunks-webpack-plugin from combining all CSS

I am using Webpack 4 to build a simple website with an express backend. Now that I am implementing a custom element I am confronted with an issue regarding the shadow DOM.
The issue is as follows: all of my SCSS is being combined into one CSS output file. I need it to remain separate so that the custom element's style can be dynamically added to the shadow DOM, when the element is connected.
I am using extract-css-chunks-webpack-plugin (which I think the issue is with), css-loader, postcss-preset-env and sass-loader to handle all SCSS within the app/site.
All my searching thus far has simply lead me to the exact opposite of what I need (people trying to combine their SCSS).
I understand I could build the custom element separately and then just import it into the project after it has been built but that means managing two building environments and then having to version control across both -- seems like a lot of overhead.
The project's folder structure is as follows:
root
--src/
----assets/
------js/
--------main.js
------scss/
--------main.scss
------web-components/
--------contact-modal.js
--------scss/
----------modal.scss
My current webpack dev config is as follows:
**omitted**
module: {
rules: [{
test: /\.(scss)$/,
use: [{
loader: ExtractCssChunksPlugin.loader,
options: {
hot: true,
}
},
{
loader: 'css-loader',
options: {
sourceMap: true,
}
},
{
loader: 'postcss-loader',
options: {
indent: 'postcss',
plugins: () => postcssEnv(),
sourceMap: 'inline',
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
**omitted**
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: 'src/views/pages/index.ejs',
filename: 'index.html',
}),
new ExtractCssChunksPlugin({
filename: 'assets/css/[name].css',
chunkFilename: 'assets/css/[id].css',
})
]
If there is a better way of using custom elements which I have overlooked I'd appreciate any feedback.
Thank you in advance.
EDIT:
Figure it would be beneficial to state that I am including the modal.scss file with an import in the contact-modal.js file.
I'm assuming modal.scss is importing main.scss? If that's so, then your issue is with the Sass compiler itself, not webpack. Depending on what's in modal.scss, you may want to use #use instead
Edit 1:
If you're adding your compiled css in the shadow DOM in let's say a <style> tag, you can replace the ExtractCSSChunks loader with something like to-string-loader. In your js, import style from "modal.scss"; will have the compiled output in a string that you can use.
In order to solve my issue while still using SCSS (to allow me to use vendor prefixing from postcss-loader) I ended up prefixing my modal scss with a .modal flag so modal.scss became main.modal.scss.
I then edited my webpack config to have two rules for scss files: One which only affected .scss files and one which affected .modal.scss.
Then, in my modal I imported the scss with a normal import style from './main.modal.scss'; to then append it to the shadow DOM in a <style></style> element.
Code is as follows:
New SCSS rule
test: /(\.modal\.scss)$/,
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => [ postcssPresetEnv() ],
sourceMap: 'inline'
}
},
'sass-loader'
]
Modified old SCSS rule
test: /(?<!\.modal)\.scss$/,
use: [{
loader: ExtractCSSChunksPlugin.loader,
options: {
hot: true,
}
},
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 3
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
postcssPresetEnv()
],
sourceMap: 'inline'
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
}
}
]
In my contact-modal.js file
import CSS from './scss/main.modal.scss';
// ... omitted ...
connectedCallback() {
// ... omitted ...
const style = document.createElement('style');
style.innerHTML = CSS.toString();
this.shadow.appendChild(style);
// ... omitted ...
}

Webpack 4 extract css from scss not removing the sass file from complied file

I have gone through a lot of questions on stackoverflow and article before writing this question here.
I am successfully able to create the CSS file sass using webpack4.
I have file as below client.js, it import the scss
import React , { Component } from 'react'
import { connect } from 'react-redux';
import './jobcard.scss';
here is my webpack config.
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
client: './src/client.js',
},
output: {
path: path.resolve(__dirname, 'asset'),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'main.css',
})
]
}
It successfully creating the main.css and store in the '/asset' folder.
but the problem is when I complied client.js using babel. it has below the line.
require("./jobcard.scss");
its breaks due to the above line because in dist folder there is no such scss file as it's extract and placed in 'asset' folder. I want my css/image in 'asset' folder.
my expectation is my final css moved to '/asset' folder which is happening right now and the above line should get removed from complied client.js file.
So I can refer the main.css on my index.html from asset location.
Try with this config to see if it work for you
module: {
rules: [{
test: /\.scss$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
minimize: true,
sourceMap: true
}
},
{
loader: "sass-loader"
}
]
}
]
}

webpack working with font

I am trying to use webpack2 with express, and I just can't seem to make my font served, js file works fine, please,help
this is my webpack.config
const devConfig = {
devtool: '#source-map',
entry: [
'./public/js/entry.js',
'webpack/hot/dev-server',
'webpack-hot-middleware/client'
]
,
output: {
filename: './js/main.js',
path: '/',
publicPath: publicPath
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
],
module: {
rules: [
{
test: /\.s(a|c)ss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
},
{
test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
loader: 'file-loader?'
}
]
}
};
and inside my scss file, I have this
src: url('../font-files/firasans-extralightitalic-webfont.woff2') format('woff2'), url('../font-files/firasans-extralightitalic-webfont.woff') format('woff');
}
and my path structure
while I keep getting this error
Module not found: Error: Can't resolve '../font-files/firasans-extralightitalic-webfont.woff2'
can anyone tell me what's wrong...I see some others add there fonts in js file, but I really don't like do it that way
ok, I've struggle another couple hours, now, I find out how to make it work.
the idea is we write relative path in #font-face, but the path is relative to the entry, in my case, the entry is style.sass, so I wrote this
src: url('./font-files/firasans-extralightitalic-webfont.woff2')
now I can resolve this files correctly

How to include this node_module's .html asset in webpack?

I am using the package electron-notifications and it relies on a .html and .css file in its assets folder. This assets folder is not included in webpack (1.14.0) though.
I know I should not add a module as an entry point. I have come across a concept called code splitting, but I'm not clear on how that works and if that is what I need to be looking into further. Any advice you can give would be greatly appreciated.
webpack.config.production.js
import path from 'path';
import webpack from 'webpack';
import validate from 'webpack-validator';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import merge from 'webpack-merge';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import BabiliPlugin from 'babili-webpack-plugin';
import baseConfig from './webpack.config.base';
export default validate(merge(baseConfig, {
devtool: 'inline-source-map',
entry: [
'babel-polyfill',
'./app/index'
],
output: {
path: path.join(__dirname, 'app/dist'),
publicPath: '../dist/'
},
module: {
loaders: [
// Extract all .global.css to style.css as is
{
test: /\.global\.css$/,
// loaders: [
loader: ExtractTextPlugin.extract(
'style-loader',
'css-loader?sourceMap'
)
// ]
},
// Pipe other styles through css modules and append to style.css
{
test: /^((?!\.global).)*\.css$/,
// loaders: [
loader: ExtractTextPlugin.extract(
'style-loader',
'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
)
},
// Fonts
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream' },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file' },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml' },
// Images
{
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
loader: 'url-loader'
}
]
},
plugins: [
// https://webpack.github.io/docs/list-of-plugins.html#occurrenceorderplugin
// https://github.com/webpack/webpack/issues/864
new webpack.optimize.OccurrenceOrderPlugin(),
// NODE_ENV should be production so that modules do not perform certain development checks
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new BabiliPlugin(),
new ExtractTextPlugin('style.css', { allChunks: true }),
new HtmlWebpackPlugin({
filename: '../app.html',
template: 'app/app.html',
inject: false
})
],
// https://github.com/chentsulin/webpack-target-electron-renderer#how-this-module-works
target: 'electron-renderer'
}));
If you want that packages' CSS to be recognised by the webpack, you just add it to the style's(CSS's) loader block, as an include attribute along with "test" and "loader". In the include attribute point it to the node_modules/electron_notification path.
HTML of that package need not be included, since your Single Page Application, has it's own HTML, if needed try to replicate the class names there. But I doubt if you need to do that.

Categories