Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional build based on environment using Webpack

I have some things for development - e.g mocks which I would like to not bloat my distributed build file with.

In RequireJS you can pass a config in a plugin file and conditonally require things in based on that.

For webpack there doesn't seem to be a way of doing this. Firstly to create a runtime config for an environment I have used resolve.alias to repoint a require depending on the environment, e.g:

// All settings.
var all = {
    fish: 'salmon'
};

// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require('envsettings'));

Then when creating the webpack config I can dynamically assign which file envsettings points to (i.e. webpackConfig.resolve.alias.envsettings = './' + env).

However I would like to do something like:

if (settings.mock) {
    // Short-circuit ajax calls.
    // Require in all the mock modules.
}

But obviously I don't want to build in those mock files if the environment isn't mock.

I could possibly manually repoint all those requires to a stub file using resolve.alias again - but is there a way that feels less hacky?

Any ideas how I can do that? Thanks.

like image 834
Dominic Avatar asked Feb 17 '15 22:02

Dominic


3 Answers

You can use the define plugin.

I use it by doing something as simple as this in your webpack build file where env is the path to a file that exports an object of settings:

// Webpack build config
plugins: [
    new webpack.DefinePlugin({
        ENV: require(path.join(__dirname, './path-to-env-files/', env))
    })
]

// Settings file located at `path-to-env-files/dev.js`
module.exports = { debug: true };

and then this in your code

if (ENV.debug) {
    console.log('Yo!');
}

It will strip this code out of your build file if the condition is false. You can see a working Webpack build example here.

like image 192
Matt Derrick Avatar answered Nov 17 '22 14:11

Matt Derrick


Not sure why the "webpack.DefinePlugin" answer is the top one everywhere for defining Environment based imports/requires.

The problem with that approach is that you are still delivering all those modules to the client -> check with webpack-bundle-analyezer for instance. And not reducing your bundle.js's size at all :)

So what really works well and much more logical is: NormalModuleReplacementPlugin

So rather than do a on_client conditional require -> just not include not needed files to the bundle in the first place

Hope that helps

like image 27
Roman Zhyliov Avatar answered Nov 17 '22 13:11

Roman Zhyliov


Use ifdef-loader. In your source files you can do stuff like

/// #if ENV === 'production'
console.log('production!');
/// #endif

The relevant webpack configuration is

const preprocessor = {
  ENV: process.env.NODE_ENV || 'development',
};

const ifdef_query = require('querystring').encode({ json: JSON.stringify(preprocessor) });

const config = {
  // ...
  module: {
    rules: [
      // ...
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: `ifdef-loader?${ifdef_query}`,
        },
      },
    ],
  },
  // ...
};
like image 47
May Oakes Avatar answered Nov 17 '22 14:11

May Oakes