Of course I have a backup!

Random blobs of wisdom about software development

Sass with sourcemaps, webpack, and live reload

Monday, August 17, 2015

Two days ago, I would have told you just how much of a poor, poor soul you are. Because it's simply not possible, but the READMEs make you chase the dragon, leading you to believe that it is possible. But alas, no, none of the methods work. After spending hours, you will find out that you can have either source maps, or live reload. Not both. Pick one. But yeah that was two days ago, read on.

So it turns out that it is, in fact, possible, it's just that the README in sass-loader is incorrect, and leads you on a false path:

Source maps Because of browser limitations, source maps are only available in conjunction with the extract-text-webpack-plugin. Use that plugin to extract the CSS code from the generated JS bundle into a separate file (which even improves the perceived performance because JS and CSS are downloaded in parallel).

WRONG. Do not do this. After getting the aforementioned extract-text-plugin to work, which wasn't entirely straightforward, since I was using it with react-hot-loader, and the dev server, and the whatnot, it turns out that live reload does not work. But why, it was working just fine before? So you revert everything, and confirm that live reload works if you don't use extract-text, which leaves you with a choice:

  • Use extract-text to get sourcemaps
  • Skip extract-text, get live reload, but no source maps

After googling around, I found a closed ticket on the extract-text repository where people talk about this, and there is a note:

This doesn't work. You shoudn't use the extract-text-webpack-plugin in development. Better thread the extract-text-webpack-plugin as production optimiation for the style-loader.

But after asking for confirmation if sourcemaps and live reload is really not possible at the moment with webpack, @sokra comes with the solution:

Doesn't style-loader!css-loader?sourceMap work?

Well, it does not, but after a bit of trial and error, it turns out that if you add it to both the sass loader, and the css loader:

module: {
  loaders: [
    {
      test: /\.scss$/,
      loaders: [ 'style', 'css?sourceMap', 'sass?sourceMap' ]
    }
  ]
}

And then use it with the usual require('../../theme/default/main.scss') in one of your javascript files (you could use import too, if you are doing ES6), it will work. It does produce a bit of a weird output in Chrome, but the rules are shown correctly, and clicking on the file takes you to the correct SCSS file, and the correct line number.

So to recap:

  1. Do not use extract-text for source maps, it was made for extracting out your CSS/SCSS/etc into separate CSS files
  2. Do not do what the sass-lodaer README tells you, use what I have shown above
  3. Require your style from your JS file

As a side note, I find it very weird that webpack advocates using require('style.css'); from javascript by default, and delegates extracting out to CSS to a separate plugin. I would expect it the other way around, but hopefully I'll find out why it's done this way.

This was written by Norbert Kéri, posted on Monday, August 17, 2015, at 17:01

Tagged as:
Ardon wrote
Thank you for this article! It worked great.

2015-09-30 17:14:27

mitch wrote
Thanks for the article. Helpful, but I'm having some problems with sourcemaps -- live reloading works great, and sourcemaps work initially, but they don't actually update.

I change my .scss file and the new styles hot load into the app, but if i click the filename next to the style in the inspector (which looks like this: https://monosnap.com/file/r2NrgmNxVInVxuDv4Du4UMCg1M2bmZ), the .scss file still shows the content it had at load time. It's as if chrome isn't refreshing with the new sourcemaps that come across the wire during a hot load.

have you come across this? any idea?
[js]
loaders: ['style', 'css?sourceMap', 'sass?sourceMap']
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
[/js]

2015-11-19 02:15:14

Norbert Kéri wrote
@mitch
Unfortunately no, it works fine for me (for now, at least). I'd recommend opening a ticket on github, specify your version numbers in package.json, and your full webpack config, someone might be able to point out the problem.

2015-12-06 14:27:11

Matt Smith wrote
THANK YOU!!

2015-12-15 09:18:35

Mark Norgate wrote
I'm having real trouble getting SASS up and working in my webpack project. I've run through this article but I still get the error, "ERROR in Cannot find module 'source-map' @ ./src/app//sass/authenty.scss 4:14-141"

Does anyone know of a github (for example) that demonstrates a working SASS compiler within webpack? Or would someone be kind enough to share such a project?

2015-12-15 13:38:13

Juan B. Rodriguez wrote
Hello, just wondering what theme is that on your editor ?

2015-12-20 17:09:31

Norbert Kéri wrote
It's called "midnight", and provided by SyntaxHighlighter.

2016-01-25 16:29:35

dSebastien wrote
Awesome! Thanks!

2016-02-13 00:28:02

Emma Wu wrote
Just Saved My Day!
But There's still two problems remained.
1. The code line reference is not correct. It only refer to the first css selector position. In most my partial css file, I'll use a id selector in the very beginning. Thus in most situation, it only references the first line of code.
2. Live reload still refreshes the page.

2016-08-24 09:24:49

Emma Wu wrote
My mistake about the live reload still refreshing the page.
But however, regarding the first problem, I still can't fix it.
And I found a issue about this one: https://github.com/sass/node-sass/issues/1206. It seems that the latest version of node-sass has fixed this issue. But the problem remains in my app..

2016-08-29 07:20:08

Ash wrote
This is simply genius. Thank you very much for the effort. It worked very well. I am using webpack2 and below is the relevant config

const styleLoader = PRODUCTION ? ['css-loader', 'sass-loader'] : ['css-loader?sourceMap', 'sass-loader?sourceMap'];
module: {
rules: [
{
test: /\.js$/,
use: [
'babel-loader',
],
exclude: /node_modules/
},
{
test:[ /\.css$/, /\.scss$/],
use: ExtractTextPlugin.extract({
use: styleLoader
}),
exclude: /node_modules/
},
{
test: /\.js$/,
use: [
'eslint-loader',
],
exclude: /node_modules/
},
{
test: /\.svg$/,
use: [
'svg-inline-loader',
],
exclude: /node_modules/
}
],
},

2017-05-09 10:26:24

Post a comment

Providing your email is optional, it is never published or shared, it is only used for auto approval purposes. If you already have at least 1 approved comment(s) tied to your email, you don't have to wait for moderation, otherwise the author must approve your comment.

Please solve this totally random captcha