Search code examples
webpackwebpack-plugin

Webpack DefinePlugin slowness. Any alternative?


We use Webpack DefinePlugin to generate output bundle for different render modes. So for example, our webpack config will return

  [{
    entry: {
      mode1: "./input.es6",
    },
    output: {
      path: path.join(__dirname, 'dist'),
      filename: "[name]-bundle.js",
    },
    plugins: [
      new webpack.DefinePlugin({
        __RENDER_MODE__: 'mode1',
      }))
    ]
  },{
    entry: {
      mode2: "./input.es6",
    },
    output: {
      path: path.join(__dirname, 'dist'),
      filename: "[name]-bundle.js",
    },
    plugins: [
      new webpack.DefinePlugin({
        __RENDER_MODE__: 'mode2',
      }))
    ]
  }]

In the code we will do

if (__RENDER_MODE__ === 'mode1') {
  require('jquery-ui')
}

if (__RENDER_MODE__ === 'mode2') {
  require('other-lib')
}

This allows us to generate bundles that are more optimized for each render mode. However, as our render mode increases, we are running multiple webpack compilations, drastically slowing down the compilation process. I have some thoughts in solving this problem and want to hear more inputs:

  1. Is there a way to use 1 single webpack compilation and do define plugin replacement after the compilation completed? So instead of having DefinePlugin replacing the variables at the time of compilation, we only compile once and then do the replacement afterwards.

  2. Or, is there a way to do per entry DefinePlugin? Each entry will have a separate DefinePlugin configuration.


Solution

  • You have to execute what webpack does with DefinePlugin in the compile process for the simple reason that what DefinePlugin does can affect what's actually in the bundle.

    If you have the following in your code:

    if (__RENDER_MODE__ === 'mode1') {
      require('someLibrary').render();
    }
    

    webpack will be smart enough to see the IF is always falsey when the condition is not true, and someLibrary will only be added to your bundle if it can actually be used. Using DefinePlugin before the minification step is also important, as dead code (same as in the example) will be removed by the minifier.

    So, in short, no, there is no way to do what DefinePlugin does at a later point to avoid compiling both bundles separately.

    On your second question, no, a separate DefinePlugin per entry is not possible, for the simple reason that both entries may have modules in common, which would result in a conflict. The only way to do this is with two separate builds, as you're already doing.