It is not trivial to compile an SCSS file with Webpack, which is not included in the JS file, into its own CSS file. This post shows you how to do that.
Update from September 6, 2018: I updated the post to show a solution with Webpack 4.
Update from October 28, 2022: The css-loader syntax changed, as Nick pointed out in his comment.
I needed this because I had to use Webpack for a project and did not want to use another tool for compiling the SASS. At the end of my search, the solution was to use the extract-loader.
This is my webpack.config.json
:
const path = require('path');
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
entry: ['./blocks/index.js', './blocks/editor.scss', './blocks/frontend.scss'],
output: {
path: path.resolve(__dirname, 'assets'),
filename: 'js/editor.blocks.js',
},
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: 'css/[name].blocks.css',
}
},
{
loader: 'extract-loader'
},
{
loader: 'css-loader?-url'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
}
]
}
};
Code language: JavaScript (javascript)
With that, Webpack compiles the ./blocks/editor.scss
to the editor.blocks.css
inside the assets/css
directory and the ./blocks/frontend.scss
to the assets/css/frontend.blocks.css
. The postcss-loader
runs Autoprefixer. To get that working, I created a postcss.config.js
with the following content:
module.exports = {
plugins: {
'autoprefixer': {}
}
}
Code language: JavaScript (javascript)
These are the dev dependencies from my package.json
(a few are not necessary for the Webpack task) and the NPM tasks to run Webpack:
"scripts": {
"build:dev": "webpack",
"build:production": "cross-env NODE_ENV=production webpack",
"watch": "webpack --watch"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@wordpress/babel-preset-default": "^2.1.0",
"@babel/runtime-corejs2": "^7.0.0",
"autoprefixer": "^9.1.3",
"babel-loader": "^8.0.0",
"cross-env": "^5.2.0",
"css-loader": "^1.0.0",
"extract-loader": "^2.0.1",
"file-loader": "^2.0.0",
"node-sass": "^4.9.3",
"postcss-cli": "^6.0.0",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"webpack": "^4.17.2",
"webpack-cli": "^3.1.0"
},
Code language: JavaScript (javascript)
Now, if I run the webpack
command, I get my SASS compiled into CSS.
Thanks for writing this up! Helped me get Sass compiling in my project ๐
Happy to hear that, thanks for your comment! ๐
Thanks Florian, didn't think this was possible, saved my day!
Great to hear that Rei, Iโm happy that it was helpful, thanks for commenting!
Hello Florian. Thanks for this tuto, but it is not woeking for me. I am using Webpack 4. I did all your changes, but when i execute 'npm webpack' i recieve an error:
"ERROR in .[...filepath...]
Module build failed (from ./node_modules/postcss-loader/lib/index.js):
TypeError: Cannot read property 'type' of undefined"
Do you know what can be wrong here? Thanks!
Hi Josh,
I updated the post to show a working example with Webpack 4. Would you give it a try and test if that fixes the problem (the dependencies in the
package.json
also changed)?Best,
Florian
Nice tutorial you got there! Works for me, and it is pretty straightforward. Thanks!
Hi Royyan,
thanks for your comment, Iโm happy to hear that! ๐
Best,
Florian
Hi Florian, Thanks for the tutorial. It really saves my day. Hovewer, i wonder if you have any idea about uglyfy or minify the CSS output. Thanks in advance.
Hi Bayu,
happy to hear that it was helpful, thanks for the comment! ๐
I didnโt implement it yet, but minifying should be possible with something like that: https://github.com/NMFR/optimize-css-assets-webpack-plugin (came about it via the readme of https://github.com/webpack-contrib/mini-css-extract-plugin). Hope that helps!
Best,
Florian
Thank a lot for this tutorial
Thank you so much for this tutorial. It has helped me out a lot!!
I have two questions:
1. Googled this and couldn't find an answer, why do you enter the css-loader, like this ''css-loader?-url"?
2. Any insights into how to generate sourcemaps?
I spent the whole day trying different alternatives but keep getting different errors and getting nowhere.
Thank you so much!!
Hi Mauricio,
thanks for the comment, glad the post is helpful! ๐
To your first question: That is to prevent inlining of things that are loaded via
url()
in the CSS: https://github.com/webpack-contrib/css-loader/issues/44To your second question: not really, sorry. I did not work on really setting up a webpack config for some time now, I am using the NPM package
@wordpress/scripts
now that comes with a webpack config, that creates source maps for JS code.Best,
Florian
I see. Thank you for the clarifications Florian. I'll take a look at the package that you mentioned.
Youโre welcome! Hope you get it working.
wow after 3 different methods, this actually worked! Thanks for this. Also saved my day. Do you maybe have also a solution for solving import that need globbing?
So for example @import "variables/**/*";
Hi Steffi,
no, sorry, did not need that yet.
Best,
Florian
The syntax for css-loader has changed, took me a few attempts to find it.
Changing
{ loader: 'css-loader?-url' },
to
{ loader: 'css-loader', options: { url: false } },
makes things run again.
Otherwise, extract-loader gets stuck on the import directive in the emitted JS. See the updated GitHub issue that you already linked above: https://github.com/webpack-contrib/css-loader/issues/44#issuecomment-326923086
Thanks for sharing, Nick! Will link to your comment in the update box.