使用Webpack基于环境的条件构build

我有一些发展的东西 – 例如嘲笑,我不想膨胀我的分布式构build文件。

在RequireJS中,你可以在一个插件文件中传递一个configuration文件,并根据这个configuration文件需要一些东西。

对于webpack来说,似乎没有办法做到这一点。 首先为一个环境创build一个运行时configuration,我已经使用resolve.alias来根据环境重新指定一个require,例如:

// All settings. var all = { fish: 'salmon' }; // `envsettings` is an alias resolved at build time. module.exports = Object.assign(all, require('envsettings')); 

然后当创buildwebpackconfiguration我可以dynamic地分配哪个文件envsettings指向(即webpackConfig.resolve.alias.envsettings = './' + env )。

不过,我想做一些事情:

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

但是,如果环境不是模拟的,显然我不想在这些模拟文件中构build。

我可能会手动重新使用所有需要的存根文件再次使用resolve.alias – 但有没有一种方法,感觉lesshacky?

任何想法,我可以做到这一点? 谢谢。

你可以使用define插件 。

通过在webpack构build文件中执行如此简单的操作来使用它,其中env是导出设置对象的文件的path:

 // 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 }; 

然后在你的代码中

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

如果条件为假,它将从编译文件中除去这些代码。 您可以在这里看到一个可用的Webpack构build示例 。

另一种方法是使用JS文件作为proxy ,并让该文件加载commonjs中感兴趣的模块,并将其导出为es2015 module ,如下所示:

 // 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 

那么你通常可以在你的应用中使用ES2015模块:

 // myApp.js import { myString } from './store/myModule.js' myString // <- "this is in dev" 

不知道为什么“webpack.DefinePlugin”答案是定义基于环境的导入/需求的最佳select。

这种方法的问题在于,您仍然将所有这些模块交付给客户端 – 例如,使用webpack-bundle-analyezer进行检查。 而不是减less你的bundle.js的大小:)

那么,真正的效果和更合乎逻辑的是: NormalModuleReplacementPlugin

所以,而不是做一个on_client有条件的要求 – >只是不包括不需要的文件到捆绑首先

希望有所帮助

我结束了使用类似于马特·德里克的答案 ,但担心两点:

  1. 每次使用ENV (这对大型configuration都不好)时,会注入完整的configuration。
  2. 我必须定义多个入口点,因为require(env)指向不同的文件。

我想到的是一个简单的composer php,它build立一个configuration对象,并将其注入到configuration模块。
这是Iam使用的文件结构:

 config/ └── main.js └── dev.js └── production.js src/ └── app.js └── config.js └── ... webpack.config.js 

main.js保存所有的默认configuration的东西:

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

dev.jsproduction.js只保存覆盖主configuration的configuration文件:

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

重要的部分是组成configuration的webpack.config.js ,并使用DefinePlugin生成一个包含组合configuration对象的环境variables__APP_CONFIG__

 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)) }) ] }; 

最后一步是config.js ,看起来像这样(使用es6导入导出语法,因为它在webpack下):

 const config = __APP_CONFIG__; export default config; 

在你的app.js你现在可以使用import config from './config'; 获取configuration对象。

使用ifdef-loader 。 在你的源文件中,你可以做类似的东西

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

相关的webpackconfiguration是

 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}`, }, }, ], }, // ... }; 

虽然这不是最好的解决scheme,但它可能会满足您的一些需求。 如果你想在节点和浏览器中运行不同的代码,使用这个工作对我来说:

 if (typeof window !== 'undefined') return } //run node only code now