mini-css-extract-plugin + sass-loader + splitChunks

Created on 21 Mar 2018  ·  9Comments  ·  Source: webpack-contrib/mini-css-extract-plugin

I've the follow example configuration to use mini-css-extract-plugin with Webpack 4:

entry: {
   a: ['./js/a.js', './scss/a.scss'],
   b: ['./js/b.js', './scss/b.scss']
},
module: {
    rules: [
       [...],
       {
        test: /\.(css|sass|scss)$/,
        use: [
            MiniCssExtractPlugin.loader,
            {
                loader: 'css-loader',
                options: {
                    importLoaders: 2,
                    sourceMap: true
                }
            },
            {
                loader: 'postcss-loader',
                options: {
                    plugins: () => [
                        require('autoprefixer')
                    ],
                    sourceMap: true
                }
            },
            {
                loader: 'sass-loader',
                options: {
                    sourceMap: true
                }
            }
        ]
},
optimization: {
    splitChunks: {
        cacheGroups: {
            js: {
                test: /\.js$/,
                name: "commons",
                chunks: "all",
                minChunks: 7,
            },
            css: {
                test: /\.(css|sass|scss)$/,
                name: "commons",
                chunks: "all",
                minChunks: 2,
            }
        }
    }
},
plugins: [
    new MiniCssExtractPlugin({
        filename: "dist/[name].css",
    }),
]

And the following sass files:

// a.scss
@import 'global.scss';
@import 'vendor.css';
[...] 

// b.scss
@import 'global.scss';
@import 'vendor.css';
[...]

When I run webpack vendor.css is inserted in in commons.css bundle while global.scss not.

In general every import of .css file get processed by splitChunks option (only if extension .css is specified in the name) while .scss files not.

I have a project with multiple sass entry point and many @import of sass component and I'd like to create a common bundle with shared sass modules.

The chunk of js files works properly.

Most helpful comment

@KytoSai
you need

            {
                test: /\.scss$/,
                use: [
                    'style-loader', // or MiniCssExtractPlugin.loader
                    { loader: 'css-loader', options: { sourceMap: true, importLoaders: 1 } },
                    { loader: 'sass-loader', options: { sourceMap: true } },
                ],
            },

then you can use like

// style/index.js
import '../base.scss';
import './layout.scss';
import './nav-component.scss';

import './component/v-base-nav.scss';
import './component/v-nav-dropdown.scss';
import './component/v-realtime-nav.scss';

All 9 comments

I have the same problem, the scss imports are not chunked (or bad), it seems it's a missing feature from sass-loader which export all scss in one module.

See: https://github.com/webpack-contrib/sass-loader/issues/455

The only solution for the moment is to have only one entry for scss, it results on one big css.

Just to clarify, with the above configuration i get:
a.css => A css/scss bundle
b.css => B css/scss bundle
common.css => common css only and not common scss import.

@okamiconcept do you mean I have to create manually a common.scss as entry file?

@Loykos Yes If you want to create a common css, you have to build it yourself, i hope another person have a better solution to that! :)

This is a problem with, I believe, all compile-to-css languages unless you take particular care to not use @import or use it in a way that can be not converted by the compiler itself.

Basically, they work like a C preprocessor #include, and will just inline the source code of the @import. To webpack, you're really only importing a _single_ .css file, and not a .css file that imports other .css files.

I think of a solution.
Change the entry file scss to js file.

I try put import a.scss to a.js. It not work...! :(

@KytoSai
you need

            {
                test: /\.scss$/,
                use: [
                    'style-loader', // or MiniCssExtractPlugin.loader
                    { loader: 'css-loader', options: { sourceMap: true, importLoaders: 1 } },
                    { loader: 'sass-loader', options: { sourceMap: true } },
                ],
            },

then you can use like

// style/index.js
import '../base.scss';
import './layout.scss';
import './nav-component.scss';

import './component/v-base-nav.scss';
import './component/v-nav-dropdown.scss';
import './component/v-realtime-nav.scss';

Yes, I moved style import inside js entry files and it's working

webpack.config.js

entry: {
   a: ['./js/a.js',  => './scss/a.scss' <=],
   b: ['./js/b.js',  => './scss/b.scss' <=]
},

CSS Entrypoints are not officially supported (yet), it might look like it works but that's not the case and additionally one will get a useless JS file per CSS entrypoint containing only the webpack runtime. Don't use CSS Files as entrypoints, import into the JS entry intead

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dmitrybelyakov picture dmitrybelyakov  ·  3Comments

BODhaha picture BODhaha  ·  3Comments

skrobek picture skrobek  ·  4Comments

grrowl picture grrowl  ·  3Comments

TheHolyWaffle picture TheHolyWaffle  ·  4Comments