Css-loader: Exporting variables from SCSS file to JavaScript no longer works in css-loader 4.x.x

Created on 25 Aug 2020  路  3Comments  路  Source: webpack-contrib/css-loader

  • Operating System: Windows 10
  • Node Version: v10.17.0
  • NPM Version: 6.13.2
  • webpack Version: 4.44.1
  • css-loader Version: 4.2.1

Other:
sass-loader: "8.0.2",
style-loader: "1.2.1",

Expected Behavior

In version CSS-loader 3.x.x I was able to import SCSS variables but since I migrated to css-loader 4.x.x this no longer works, now I get an empty object.

Example:
webpack.config.js

                {
                    test: /\.(css|scss|sass)$/,
                    loader: [
                         'style-loader',
                         'css-loader',
                        'sass-loader'
                    ],
                }

_export.scss

// variables.scss
$white-color: #fcf5ed;
$dark-color: #402f2b;
$light-color: #e6d5c3;

// the :export directive is the magic sauce for webpack
:export {
  whitecolor: $white-color;
  darkcolor: $dark-color;
  lightcolor: $light-color;
}

somefile.js

const variables = require("../../../../../theme/_export.scss");
console.log(variables)

With css-loader 3.x.x and older everything works fine as expected. I get variables as an object containing the values
{
whitecolor: "#fcf5ed";
darkcolor: "#402f2b";
lightcolor: "#e6d5c3"
}

Actual Behavior

Since migrated to css-loader 4.x.x instead of the expected values I get an empty object {}
If I role back to an older version of css-loader everything works again as expected.

Code

This is a full copy of my webpack.config.js

'use strict';

const path = require('path');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const TerserPlugin = require('terser-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = (env, argv) => {
    const mode = argv.mode || process.env.NODE_ENV;
    console.log("Mode: " + mode);
    return {
        entry: ['./src/index.tsx'],
        output: {
            path: path.resolve(__dirname, "dist"),
            filename: 'index.js'
        },
        devtool: mode === 'production' ? undefined : "inline-source-map",
        module: {
            rules: [
                {
                    test: /\.(ts|tsx)$/,
                    enforce: 'pre',
                    exclude: /node_modules/,
                    include: /src/,         
                    use: [
                        {
                            loader: "eslint-loader",
                            options: {
                                fix: true
                            }
                        }
                    ]
                },
                {
                    test: /\.tsx?$/,
                    loader: 'ts-loader',
                    options: {
                        transpileOnly: true // IMPORTANT! use transpileOnly mode to speed-up compilation
                    }
                },
                {
                    test: /\.html$/,
                    use: [
                        {
                            loader: "html-loader",
                            options: {
                                minimize: true
                            }
                        }
                    ]
                }, {
                    test: /\.(css|scss|sass)$/,
                    loader: [
                         'style-loader',
                         'css-loader',
                        'sass-loader'
                    ],
                }, {
                    test: /\.(jpe?g|png|gif|xml|svg)$/i,
                    use: [{
                        //data-url if file size is below 5kb
                        loader: 'url-loader',
                        options: {
                            hash: 'sha512',
                            digest: 'hex',
                            name: '[hash].[ext]',
                            limit: 5000
                        }
                    }]
                }, {
                    test: /\.(woff(2)?|ttf|eot)$/,
                    use: {
                        loader: 'file-loader',
                        options: {
                            outputPath: 'fonts/'
                        }
                    }
                }]
        },
        resolve: {
            extensions: [
                '.ts',
                '.tsx',
                '.js',
                '.jsx',
                '.scss',
                '.css',
                '.svg',
                '.eof',
                '.woff',
                '.woff2',
                '.ttf',
                '.txt',
                '.xml'
            ]
        },
        plugins: [
            ...(mode === "production" ? [new MiniCssExtractPlugin({filename: "index.css"})] : []),
            new ForkTsCheckerWebpackPlugin({
                async: false
            }),
            new HtmlWebPackPlugin({
                template: "./src/index.html",
                filename: "./index.html"
            }),
            new CopyWebpackPlugin({
                patterns: [
                    {
                        from: './static',
                        globOptions: {
                            ignore: ['**/static/readme.txt']
                        }
                    }
                ]
            }),
        ],
        devServer: {
            port: 4000,
            overlay: {
                warnings: false,
                errors: true
            }
        },
        optimization: {
            minimizer: [
                new TerserPlugin({
                    terserOptions: {
                        compress: {
                            unused: false
                        }
                    }
                })
            ]
        }
    };
};

How Do We Reproduce?

Just try to export some variables in a scss files and import in a js file. It all works fine with css-loader 3.x.x or older.
With css-loader 4.x.x the imported variables are object is and empty object.

Most helpful comment

Why is this issue closed? Where is the solution? I have the same problem and I can't find any solution.

See the linked CRA 4 issue. Basically you change your css-loader options in webpack for SCSS files so the compileType is icss. Here's the change in my own config:

     test: /\.scss$/,
     use: [
-      { loader: "style-loader" },
-      { loader: "css-loader" },
+      "style-loader",
+      {
+        loader: "css-loader",
+        options: {
+          importLoaders: 1,
+          modules: {
+            compileType: "icss"
+          }
+        }
+      },

All 3 comments

https://github.com/webpack-contrib/css-loader#compiletype, we even have example in docs for this case https://github.com/webpack-contrib/css-loader#separating-interoperable-css-only-and-css-module-features

Why is this issue closed? Where is the solution? I have the same problem and I can't find any solution.

Why is this issue closed? Where is the solution? I have the same problem and I can't find any solution.

See the linked CRA 4 issue. Basically you change your css-loader options in webpack for SCSS files so the compileType is icss. Here's the change in my own config:

     test: /\.scss$/,
     use: [
-      { loader: "style-loader" },
-      { loader: "css-loader" },
+      "style-loader",
+      {
+        loader: "css-loader",
+        options: {
+          importLoaders: 1,
+          modules: {
+            compileType: "icss"
+          }
+        }
+      },
Was this page helpful?
0 / 5 - 0 ratings

Related issues

heldrida picture heldrida  路  4Comments

tapz picture tapz  路  3Comments

callmez picture callmez  路  4Comments

grydstedt picture grydstedt  路  3Comments

jerrysu picture jerrysu  路  5Comments