Search code examples
javascriptwebpackminifysource-mapsuglifyjs

How to make webpack's uglifyjs plugin not break sass's source maps?


Here's the setup:

package.json:

{
  "dependencies": {
    "css-loader": "^0.26.0",
    "extract-text-webpack-plugin": "^1.0.1",
    "html-webpack-plugin": "^2.24.1",
    "node-sass": "^3.13.0",
    "sass-loader": "^4.0.2",
    "style-loader": "^0.13.1",
    "webpack": "^1.13.3"
  }
}

webpack.config.js:

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: './1.js',
    output: {
        path: 'dist',
        filename: 'bundle.js',
    },
    module: {
        loaders: [
            {test: /\.sass$/, loader: ExtractTextPlugin.extract('style', 'css?sourceMap!sass?sourceMap')},
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'template.ejs',
        }),
        new ExtractTextPlugin('[name].css'),
        new webpack.optimize.UglifyJsPlugin(),
    ],
    devtool: 'source-map',
};

template.ejs:

<!doctype html>
<html>
<body>

<div></div>

</body>
</html>

1.js:

require('./1.sass');

1.sass:

body
    background: #ddd
div
    width: 100px
    height: 100px
    margin: auto
    background: #333

Then

$ rm -rf dist/* && ./node_modules/.bin/webpack

And open http://example.com/dist in Chrome. Then go to Developer Tools > Elements tab. Click on the div, and then on the link for div { width: 100px; ... } block. And you'll find yourself on line 2. But when you comment out the new webpack.optimize.UglifyJsPlugin() line, you'll be at line 3, as expected. What am I doing wrong?


Solution

  • First thing to mention is that UglifyJsPlugin switches all loaders into minimizing mode. From the docs:

    Minimize all JavaScript output of chunks. Loaders are switched into minimizing mode.

    But thankfully it was changed in the coming 2.x version.

    The other issue is that libsass generates wrong source map, when outputStyle is compressed. And outputStyle is compressed, when you don't specify it explicitly and minification is turned on.

    So, for now the workaround is to specify some outputStyle other than compressed:

    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
        entry: './1.js',
        output: {
            path: 'dist',
            filename: 'bundle.js',
        },
        module: {
            loaders: [
                {test: /\.sass$/, loader: ExtractTextPlugin.extract('style', 'css?sourceMap!sass?sourceMap')},
            ]
        },
        sassLoader: {
            outputStyle: 'nested',
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: 'template.ejs',
            }),
            new ExtractTextPlugin('[name].css'),
            new webpack.optimize.UglifyJsPlugin(),
        ],
        devtool: 'source-map',
    };
    

    UPD It seems there are also issues with most likely source-map package and css-loader package. So you might consider disabling minification, like in: css?sourceMap&-minimize.