Search code examples
javascriptcsswebpackwebpack-merge

Using webpack-merge to prepend loaders to a rules `use` array


I use webpack-merge to merge my webpack config files for dev and prod environments. To extract CSS in prod mode, I use the mini-css-extract-plugin. According to its documentation, I use it in place of the style-loader, which is only used during development. At this moment, my webpack config for CSS blocks looks like this:

// webpack.common.js
{
  test: /\.(sa|sc|c)ss$/,
  use: [
    process.env.NODE_ENV === `production` ? MiniCssExtractPlugin.loader : `style-loader`,
    `css-loader`,
    `postcss-loader`,
    `sass-loader`
  ]
}

This works, but since I am using webpack-merge, I want to avoid this kind of logic in my common config file. Now, I have tried to split this up like so and have webpack-merge merge the various loaders:

// webpack.common.js
{
  test: /\.(sa|sc|c)ss$/,
  use: [
    `css-loader`,
    `postcss-loader`,
    `sass-loader`
  ]
}

// webpack.dev.js
{
  test: /\.(sa|sc|c)ss$/,
  use: [
    `style-loader`,
    // webpack-merge should prepend all loaders from `webpack.common.js`
  ]
}

// webpack.prod.js
{
  test: /\.(sa|sc|c)ss$/,
  use: [
    MiniCssExtractPlugin.loader,
    // webpack-merge should prepend all loaders from `webpack.common.js`
  ]
}

Using the basic merge fn, the use arrays doesnt get merged, but replaced, which ofc leads to an error: ModuleParseError: Module parse failed: You may need an appropriate loader to handle this file type.

So I tried to use merge.smartStrategy({ 'module.rules.use': 'prepend' })(), but I get an error: TypeError: this[MODULE_TYPE] is not a function. Is there something I am missing or is this simply not possible?


Solution

  • it's a little update. In modern versions of webpack you should use mergeWithRules. In that case it looks like this

    // webpack.common.js
    {
      test: /\.(sa|sc|c)ss$/,
      use: [
        `postcss-loader`,
        `sass-loader`
      ]
    }
    
    // webpack.dev.js
    {
      test: /\.(sa|sc|c)ss$/,
      use: [
        "style-loader"
      ]
    }
    
    mergeWithRules({
      module: {
        rules: {
          test: "match",
          use: "prepend",
        },
      },
    })(common, dev);