Conditional build based on environment using Webpack

I have some things to develop - for example, mocks, which I would not want to inflate my distributed assembly file.

In RequireJS, you can pass the configuration in the plugin file and, of course, require things from it based on this.

For webpack, there seems to be no way to do this. First, to create a runtime configuration for the environment, I used resolve.alias to call the environment again, for example:

// 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 configuration, I can dynamically assign which envsettings file 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 create these layout files if the environment is not a layout.

I could manually redirect everything that is required to the stub file again using resolve.alias - but is there a way that seems less hacked?

Any ideas how I can do this? Thank.

+79
javascript conditional build webpack require
Feb 17 '15 at 22:29
source share
9 answers

You can use define plugin .

I use it, doing something as simple as this in the webpack assembly file, where env is the path to the file that exports the settings object:

 // 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 is in your code

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

It will disconnect this code from your build file if the condition is false. Here you can see a working example of a Webpack assembly .

+57
Apr 24 '15 at 15:16
source share

Not sure why the answer "webpack.DefinePlugin" is the most correct for determining import / import based on the environment.

Problem with this approach is that you deliver all these modules to the client -> check the webpack-bundle analyzer . And without reducing the size of your .js package at all :)

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

Therefore, instead of making the on_client condition mandatory โ†’ just do not include unnecessary files in the package in the first place

Hope that helps

+34
Jul 09 '17 at 8:30
source share

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

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

Appropriate webpack configuration

 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}', }, }, ], }, // ... }; 
+27
May 05 '17 at 10:56 PM
source share

I ended up using something similar to Matt Derrickโ€™s Answer , but was worried about two things:

  1. The full configuration is introduced every time I use ENV (which is bad for large configs).
  2. I have to define several entry points because require(env) points to different files.



I came up with a simple composer that creates a configuration object and injects it into the configuration module.
Here is the file structure that I use for this:

 config/ โ””โ”€โ”€ main.js โ””โ”€โ”€ dev.js โ””โ”€โ”€ production.js src/ โ””โ”€โ”€ app.js โ””โ”€โ”€ config.js โ””โ”€โ”€ ... webpack.config.js 

main.js contains all the default settings:

 // main.js const mainConfig = { apiEndPoint: 'https://api.example.com', ... } module.exports = mainConfig; 

Only dev.js configurations are stored in dev.js and production.js , which override the main configuration:

 // dev.js const devConfig = { apiEndPoint: 'http://localhost:4000' } module.exports = devConfig; 

The important part is webpack.config.js which compiles the configuration and uses DefinePlugin to generate the __APP_CONFIG__ environment __APP_CONFIG__ which contains the compiled configuration object:

 const argv = require('yargs').argv; const _ = require('lodash'); const webpack = require('webpack'); // Import all app configs const appConfig = require('./config/main'); const appConfigDev = require('./config/dev'); const appConfigProduction = require('./config/production'); const ENV = argv.env || 'dev'; function composeConfig(env) { if (env === 'dev') { return _.merge({}, appConfig, appConfigDev); } if (env === 'production') { return _.merge({}, appConfig, appConfigProduction); } } // Webpack config object module.exports = { entry: './src/app.js', ... plugins: [ new webpack.DefinePlugin({ __APP_CONFIG__: JSON.stringify(composeConfig(ENV)) }) ] }; 

The last step now is config.js , it looks like this (es6 export-import syntax is used here because it is in webpack):

 const config = __APP_CONFIG__; export default config; 

In your app.js you can now use import config from './config'; to get the configuration object.

+21
Apr 16 '17 at 10:29 on
source share

another way uses the JS file as a proxy , and let this file load the module of interest in commonjs and export it as an es2015 module , for example:

 // file: myModule.dev.js module.exports = "this is in dev" // file: myModule.prod.js module.exports = "this is in prod" // file: myModule.js let loadedModule if(WEBPACK_IS_DEVELOPMENT){ loadedModule = require('./myModule.dev.js') }else{ loadedModule = require('./myModule.prod.js') } export const myString = loadedModule 

Then you can usually use the ES2015 module in your application:

 // myApp.js import { myString } from './store/myModule.js' myString // <- "this is in dev" 
+18
Jan 09 '16 at 4:23
source share

Faced with the same problem as the OP, and due to the need for licensing not to include specific code in certain assemblies, I applied webpack-conditional-loader as follows:

In my build team, I set the environment variable for my build. For example, 'demo' in package.json:

 ... "scripts": { ... "buildDemo": "./node_modules/.bin/webpack --config webpack.config/demo.js --env.demo --progress --colors", ... 

The misunderstanding that is missing from the documentation I read is that I have to make this visible during assembly processing , ensuring that my env variable is injected into the global process, thus in my webpack.config / demo.js :

 /* The demo includes project/reports action to access placeholder graphs. This is achieved by using the webpack-conditional-loader process.env.demo === true */ const config = require('./production.js'); config.optimization = {...(config.optimization || {}), minimize: false}; module.exports = env => { process.env = {...(process.env || {}), ...env}; return config}; 

With this in mind, I can conditionally exclude everything, which ensures that any related code is correctly extruded from the resulting JavaScript. For example, in my rout.js demo content is stored outside of other assemblies, as follows:

 ... // #if process.env.demo import Reports from 'components/model/project/reports'; // #endif ... const routeMap = [ ... // #if process.env.demo {path: "/project/reports/:id", component: Reports}, // #endif ... 

This works with web package 4.29.6.

+3
Apr 22 '19 at 20:33
source share

I struggled with installing env in my webpack configs. Usually I want to install env so that it is accessible inside webpack.config.js , postcss.config.js and inside the entry point application itself (usually index.js ). I hope my findings can help someone.

The solution I found is to go into --env production or --env development , and then set the mode inside webpack.config.js . However, this does not help me make env available where I want it (see above), so I also need to explicitly set process.env.NODE_ENV , as recommended here . The most significant part that I have in webpack.config.js is given below.

 ... module.exports = mode => { process.env.NODE_ENV = mode; if (mode === "production") { return merge(commonConfig, productionConfig, { mode }); } return merge(commonConfig, developmentConfig, { mode }); }; 
+1
Apr 07 '19 at 19:55
source share

Although this is not the best solution, it may work for some of your needs. If you want to run different code in node and browser, this worked for me:

 if (typeof window !== 'undefined') return } //run node only code now 
0
Nov 06 '17 at 10:40
source share

Use environment variables to create dev and prod deployments:

https://webpack.js.org/guides/environment-variables/

0
Jan 17 '18 at 15:23
source share



All Articles