使用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有条件的要求 – >只是不包括不需要的文件到捆绑首先
希望有所帮助
我结束了使用类似于马特·德里克的答案 ,但担心两点:
- 每次使用
ENV
(这对大型configuration都不好)时,会注入完整的configuration。 - 我必须定义多个入口点,因为
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.js
和production.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
相关的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}`, }, }, ], }, // ... };
虽然这不是最好的解决scheme,但它可能会满足您的一些需求。 如果你想在节点和浏览器中运行不同的代码,使用这个工作对我来说:
if (typeof window !== 'undefined') return } //run node only code now