Webpack: How can we *conditionally* use a plugin?

Viewed 14744

In Webpack, I have the following plugins:

plugins: [
        new ExtractTextPlugin('styles.css'),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            drop_console: true,
        }),
    ]

I would like to apply the UglifyJsPlugin only for a specific target, so I tried using my intended conditional:

plugins: [
        new ExtractTextPlugin('styles.css'),
        (TARGET === 'build') && new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            drop_console: true,
        }),
    ]

However, this fails, showing the following error message:

E:\myProject\node_modules\tapable\lib\Tapable.js:164
            arguments[i].apply(this);
                         ^

TypeError: arguments[i].apply is not a function

Note that the above code is similar to having false at the end of the plugins array (which emits the same error):

plugins: [
        new ExtractTextPlugin('styles.css'),
        false
    ]

So, the question is: Is there a way to have conditional plugins on Webpack? (other than using variables?)

8 Answers

You can use this syntax which uses the spread operator

plugins: [
    new MiniCssExtractPlugin({
        filename: '[name].css'
    }),
    ...(prod ? [] : [new BundleAnalyzerPlugin()]),
],

You can use noop-webpack-plugin (noop means no operation):

const isProd = process.env.NODE_ENV === 'production';
const noop = require('noop-webpack-plugin');
// ...
plugins: [
    isProd ? new Plugin() : noop(),
]

Or better/recommended solution with no additional module:

const isProd = process.env.NODE_ENV === 'production';
// ...
plugins: [
    isProd ? new Plugin() : false,
].filter(Boolean)
// filter(Boolean) removes items from plugins array which evaluate to
// false (so you can use e.g. 0 instead of false: `new Plugin() : 0`)
plugins: [
    new ExtractTextPlugin('styles.css'),
    (TARGET === 'build') && new webpack.optimize.UglifyJsPlugin({
        compress: {
            warnings: false
        },
        drop_console: true,
    }),
].filter(Boolean)

You can use mode argument in webpack to pass development/production value to webpack config and then conditionally load plugins.

NPM Script:

"start": "webpack --watch --mode=development",
"build": "webpack --mode=production",

webpack.config.js:

module.exports = (env, argv) => {
  console.log("mode: ", argv.mode);

  const isDev = argv.mode === "development";

  const pluginsArr = [new CleanWebpackPlugin()];

  // load plugin only in development mode
  if (isDev) {
    pluginsArr.push(new ExtensionReloader({}));
  }
  return {
    entry: {},
    devtool: isDev ? "inline-source-map" : "", // generate source code only in development mode

    plugins: pluginsArr,
    output: {},
  };
};
Related