MiniCssExtractPlugin doesn't work in webpack 4 for scss

I started learning webpack. I installed version 4. I collect js and scss files. The task is to get one compressed js file, and one compressed css.

Here is the package.json:

{
  "name": "template",
  "version": "1.0.0",
  "description": "template",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --mode development --watch --open",
    "build": "webpack-dev-server --mode production --watch --open"
  },
  "author": "mashuxa",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^9.1.1",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-3": "^6.24.1",
    "css-loader": "^1.0.0",
    "mini-css-extract-plugin": "^0.4.1",
    "node-sass": "^4.9.3",
    "optimize-css-assets-webpack-plugin": "^5.0.0",
    "path": "^0.12.7",
    "postcss-cli": "^6.0.0",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.22.1",
    "webpack": "^4.16.5",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.5"
  }
}

Here is the webpack. config:

const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");


let config = {
    entry: "./src/index.js",
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "main.js",
        publicPath: "dist/"
    },
    devServer: {
        overlay: true
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: "/node_modules/",
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: [
                            "env",
                            "stage-3"
                        ]
                    }
                }
            },
            {
                test: /\.(sa|sc|c)ss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    // 'style-loader',
                    'css-loader',
                    'postcss-loader',
                    'sass-loader'
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: "style.css"
        })
    ]
};


module.exports = (env, options) => {
    let production = options.mode === "production";

    let minificatorJs = new webpack.optimize.UglifyJsPlugin({
        compress: {
            warnings: false,
            drop_console: true,
            unsafe: true
        }
    });
    if (production) {
        config.plugins.push(minificatorJs);
    }
    config.devtool = production ? false : "eval-sourcemap";


    return config;
}; 

module.exports = config;

JS files are collected and minified, styles are embedded in the style tag if you use 'style-loader', if you use MiniCssExtractPlugin.loader the main style. css is not generated. Tell me, please, what could be the problem? Or maybe there are alternative modules for webpack 4 to generate one single style file?

Author: mashuxa, 2018-08-19

1 answers

If you have problems with getting a css bundle, I will give you an example, only with compiling sass:

And so, the project directorate:

.
├── assets
│   ├── css
│   │   └── app.scss
│   └── js
│       └── app.js
├── dist
├── index.html
├── package.json
├── package-lock.json
├── static
│   ├── app.css
│   └── app.js
└── webpack.config.js

5 directories, 8 files

Package.json

{
  "name": "stackoverflow",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build-prod": "webpack --mode production"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^2.1.0",
    "mini-css-extract-plugin": "^0.5.0",
    "node-sass": "^4.11.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  }
}

Webpack.config.js

'use strict';

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');


module.exports = (env, options) => {
    return {
        entry: {
            app: './assets/js/app.js'
        },
        output: {
            filename: '[name].js',
            path: path.resolve(__dirname, "static")
        },
        module: {
            rules: [{
                test: /\.(css|scss)$/,
                use: [
                    /* // for development mode
                    {
                        loader: "style-loader",
                        options: {
                            singleton: true
                        }
                    },
                    */
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath: './static',
                            minimize: true
                        }
                    },
                    { loader: "css-loader" },
                    { loader: "sass-loader" }
                ]
            }]
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: '[name].css'
            })
        ],
        optimization: {
            minimizer: [
                new OptimizeCSSAssetsPlugin({})
            ]
        }
    };
};

App.js

import "../css/app.scss";

App.css

$primary-color: red;

.foo {
    color: $primary-color;
}

.bar {
    @extend .foo;
}

.hello {
    color: white;
    background-color: black;
}

Moreover, if you build in development mode, then it is recommended to use style-loader, instead of MiniCssExtractPlugin. loader, then the styles will spin in hot mode inside the js bundle.

If you want a css bundle there was too much junk, collect it using the "--mode production " option:

./node_modules/.bin/webpack --mode production

Otherwise, even the minimize: true option doesn't help.

 0
Author: balintawak_eskrima, 2019-01-26 19:15:41