Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using css modules with Extract Text Plugin

Webpack 2 build doesn't work as expected in production mode using css modules option in css-loader with extract-text-webpack-plugin.

the correct generated classes are created on html elements, implying that css-loader is working as intended, but the extracted css file from the extract-text-webpack-plugin is lacking the css identifiers.

I'm using a method for implementing both global css and css modules together as discussed here: https://github.com/css-modules/css-modules/pull/65 and here: https://github.com/kitze/custom-react-scripts/issues/29.

I'm using different loader tests for files which end with .css and files which end with .cssm.css indicating that they should be loaded using modules.

relevant part of config:

const extractTextPlugin = new ExtractTextPlugin({filename: '[name].[id].[contenthash].css', allChunks: true});

return {
    module: {
        rules: [
            {
                test: /\.cssm.(css|less)$/,
                loader: extractTextPlugin.extract({
                    fallbackLoader: 'style-loader',
                    loader: [
                        {
                            loader: 'css-loader',
                            query: {
                                importLoaders: 1,
                                modules: true,
                                localIdentName: '[name]_[local]_[hash:base64:5]'
                            }
                        },
                        {
                            loader: 'postcss-loader',
                            query: {
                                ident: 'postcss',
                                plugins: function() {
                                    return [
                                            require('autoprefixer')
                                    ];
                                }
                            }
                        },
                        {
                            loader: 'less-loader'
                        }
                    ]
                })
            },
            {
                test: /\.(css|less)$/,
                include: paths,
                loader: extractTextPlugin.extract({
                    fallbackLoader: 'style-loader',
                    loader: [
                        {
                            loader: 'css-loader',
                            query: {
                                importLoaders: 1
                            }
                        },
                        {
                            loader: 'postcss-loader',
                            query: {
                                ident: 'postcss',
                                plugins: function() {
                                    return [
                                            require('autoprefixer')
                                    ];
                                }
                            }
                        },
                        {
                            loader: 'less-loader'
                        }
                    ]
                })
            }
        ]
    },
    plugins: [
        extractTextPlugin
    ]
};

I have tried suggested solutions like using webpack 1 style of writing loaders, but that didn't help.

I'm using webpack version: 2.6.1 and extract-text-webpack-plugin: 2.1.2.

I also tried other versions, which didn't seem to help either.

my global css files work fine, only the imported .cssm.css files are being ignored when used with extract-text-webpack-plugin.

How do I fix the problem of css module files not being extracted properly with other global css?

like image 543
deckele Avatar asked Jul 09 '17 15:07

deckele


1 Answers

Apparently my setup was fine. The problem was that I didn't include all of my style (css/less) files in the "entry" webpack configuration. The configuration passed the build phase, but didn't process the new .cssm.less files I added in my attempt to use css modules together with regular global css.

Now everything works! For future reference I will include my updated configuration for using css modules with global css (for production and development). Apparently in the newer versions of webpack and extractTextPlugin, the exact syntax ("use" vs "loader", "options" vs "query" etc...) does not matter anymore and works both ways.

For production, I'm adding the prefix cssm on all of my css modules class names in the "localIdentName" property so that I can later use PurifyCSSPlugin and whitelist every class containing cssm:

exports.setupSeparateStyles = function(paths, cssModulesPaths) {
    const extractTextPlugin = new ExtractTextPlugin({
            filename: '[name].[contenthash].css', 
            allChunks: true
        });

    return {
        module: {
            rules: [
                {
                    test: /\.(css|less)$/,
                    include: paths,
                    exclude: /\.cssm\.(css|less)$/,
                    use: extractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: [
                            {
                                loader: 'css-loader',
                                options: {
                                    importLoaders: 1
                                }
                            },
                            'postcss-loader',
                            'less-loader'
                        ]
                    })
                },
                {
                    test: /\.(css|less)$/,
                    include: cssModulesPaths,
                    use: extractTextPlugin.extract({
                        fallback: 'style-loader',
                        use: [
                            {
                                loader: 'css-loader',
                                options: {
                                    importLoaders: 1,
                                    modules: true,
                                    localIdentName: 'cssm-[name]_[local]_[hash:base64:5]',
                                }
                            },
                            'postcss-loader',
                            'less-loader'
                        ]
                    })
                }
            ]
        },
        plugins: [
            new webpack.LoaderOptionsPlugin({
                options: {
                    postcss: [
                        require('autoprefixer')
                    ]
                }
            }),
            extractTextPlugin
        ]
    };
};

for development it's a lot simpler:

exports.setupInlineStyles = function (paths, cssModulesPaths) {
    return {
        module: {
            rules: [
                {
                    test: /\.(css|less)$/,
                    include: paths,
                    exclude: /\.cssm\.(css|less)$/,
                    use: [
                        'style-loader',
                        {
                            loader: 'css-loader',
                            options: {
                                importLoaders: 1
                            }
                        },
                        'postcss-loader',
                        'less-loader'
                    ]
                },
                {
                    test: /\.(css|less)$/,
                    include: cssModulesPaths,
                    use: [
                        'style-loader',
                        {
                            loader: 'css-loader',
                            options: {
                                importLoaders: 1,
                                modules: true,
                                localIdentName: '[name]_[local]_[hash:base64:5]'
                            }
                        },
                        'postcss-loader',
                        'less-loader'
                    ]
                }
            ]
        },
        plugins: [
            new webpack.LoaderOptionsPlugin({
                options: {
                    postcss: [
                        require('autoprefixer')
                    ]
                }
            })
        ]
    };
};
like image 194
deckele Avatar answered Oct 14 '22 01:10

deckele