使用 Webpack 基于环境的条件构建
Conditional build based on environment using Webpack
我有一些开发的东西 - 例如模拟,我不想用它膨胀我的分布式构建文件。
在 RequireJS 中,您可以在插件文件中传递配置,并基于此条件地要求内容。
对于 webpack,似乎没有办法做到这一点。首先,要为环境创建运行时配置,我使用 resolve.alias 根据环境重新指出需求,例如:
// All settings.
var all = {
fish: 'salmon'
};
// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require('envsettings'));
然后在创建 webpack 配置时,我可以动态分配envsettings
指向哪个文件(即 webpackConfig.resolve.alias.envsettings = './' + env
(。
但是我想做这样的事情:
if (settings.mock) {
// Short-circuit ajax calls.
// Require in all the mock modules.
}
但显然,如果环境不是模拟的,我不想在这些模拟文件中构建。
我可能会再次使用 resolve.alias 手动将所有这些要求重新指向存根文件 - 但是有没有一种方法感觉不那么黑客?
任何想法我该怎么做?谢谢。
您可以使用定义插件。
我通过在 webpack 构建文件中执行这样简单的事情来使用它,其中env
是导出设置对象的文件的路径:
// 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!');
}
如果条件为 false,它将从构建文件中剥离此代码。您可以在此处查看一个有效的 Webpack 构建示例。
不知道为什么是"webpack。DefinePlugin"答案是定义基于环境的导入/要求的最高答案。
这种方法的问题在于,您仍然将所有这些模块交付给客户端 - 例如>使用webpack-bundle-analyezer进行检查。而且根本不会减小捆绑包的大小.js:)
所以真正运行良好且更合乎逻辑的是:NormalModuleReplacementPlugin
因此,与其做一个on_client条件的要求 ->不如首先不要将不需要的文件包含在捆绑包中
希望有帮助
使用 ifdef-loader
.在您的源文件中,您可以执行类似操作
/// #if ENV === 'production'
console.log('production!');
/// #endif
相关webpack
配置为
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}`,
},
},
],
},
// ...
};
我最终使用了类似于 Matt Derrick 的答案,但担心两点:
- 每次我使用
ENV
时都会注入完整的配置(这对大型配置不利(。 - 我必须定义多个入口点,因为
require(env)
指向不同的文件。
我想出的是一个简单的作曲家,它构建了一个配置对象并将其注入到配置模块中。
这是文件结构,我为此使用:
config/
└── main.js
└── dev.js
└── production.js
src/
└── app.js
└── config.js
└── ...
webpack.config.js
该main.js
包含所有默认配置内容:
// main.js
const mainConfig = {
apiEndPoint: 'https://api.example.com',
...
}
module.exports = mainConfig;
dev.js
和production.js
只保存覆盖主配置的配置内容:
// dev.js
const devConfig = {
apiEndPoint: 'http://localhost:4000'
}
module.exports = devConfig;
重要的部分是组成配置并使用DefinePlugin生成环境变量__APP_CONFIG__
的webpack.config.js
,该变量包含组合的配置对象:
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';
来获取配置对象。
另一种方法是使用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"
面对与 OP 相同的问题,并且由于许可原因,需要在某些构建中包含某些代码,我采用了 webpack-conditional-loader,如下所示:
在我的构建命令中,我为我的构建设置了一个环境变量。例如package.json中的"demo":
...
"scripts": {
...
"buildDemo": "./node_modules/.bin/webpack --config webpack.config/demo.js --env.demo --progress --colors",
...
我阅读的文档中缺少的令人困惑的一点是,我必须通过确保我的 env 变量被注入到全局进程中,从而在我的 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};
有了这个,我可以有条件地排除任何内容,确保任何相关的代码都正确地从生成的 JavaScript 中剥离出来。例如,在我的路由中.js演示内容被排除在其他构建之外,因此:
...
// #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
...
这适用于 webpack 4.29.6。
我一直在努力在我的 webpack 配置中设置 env。我通常想要的是设置 env,以便可以在 webpack.config.js
、postcss.config.js
和入口点应用程序本身内部(通常index.js
(访问它。我希望我的发现可以帮助某人。
我想出的解决方案是传入--env production
或--env development
,然后在webpack.config.js
内设置模式。但是,这并不能帮助我使env
在我想要的地方可访问(见上文(,所以我还需要按照此处的建议显式设置process.env.NODE_ENV
。我webpack.config.js
最相关的部分如下。
...
module.exports = mode => {
process.env.NODE_ENV = mode;
if (mode === "production") {
return merge(commonConfig, productionConfig, { mode });
}
return merge(commonConfig, developmentConfig, { mode });
};
使用环境变量创建开发和生产部署:
https://webpack.js.org/guides/environment-variables/
我使用 string-replace-loader
来摆脱生产构建中不必要的导入,它按预期工作:捆绑包大小变小,并且用于开发目的的模块(redux-logger(完全从中删除。以下是简化的代码:
- 在文件
webpack.config.js
中:
rules: [
// ... ,
!env.dev && {
test: /src'/store'/index'.js$/,
loader: 'string-replace-loader',
options: {
search: /import.+createLogger.+from.+redux-logger.+;/,
replace: 'const createLogger = null;',
}
}
].filter(Boolean)
- 在文件
src/store/index.js
中:
// in prod this import declaration is substituted by `const createLogger = null`:
import { createLogger } from 'redux-logger';
// ...
export const store = configureStore({
reducer: persistedReducer,
middleware: createLogger ? [createLogger()] : [],
devTools: !!createLogger
});
虽然这不是最好的解决方案,但它可能适用于您的某些需求。如果你想在节点和浏览器中运行不同的代码,这对我有用:
if (typeof window !== 'undefined')
return
}
//run node only code now
- 我应该如何从xml文件构建一个javascript页面
- 通过js在新选项卡中有条件地打开url
- 我已经创建了一个jquery转盘,并使用if条件来运行和停止转盘
- 如何在DOM元素上按类型构建此函数
- jQuery-有条件地附加HTML
- 根据某些条件在视图之间切换
- 如何做到这一点,使代码在不传递条件后执行函数
- 有条件更新d3.js力图中节点的最佳方法
- Sencha Touch构建-排除文件
- javascript中的布尔条件
- 使用 Webpack 基于环境的条件构建
- 如何在猫鼬中构建条件查询
- 如何在动态构建 HTML 时保持 if 条件
- Javascript 有条件地构建 mvc actionlink
- 在Windows 8 Metro Javascript应用程序中构建特定的条件符号
- 如何构建一个动态if条件
- 为PHP Mailer构建消息的条件语句
- 构建条件猫鼬查询
- 我如何在JS中构建一个数组,其中一些元素是有条件的
- 基于html属性为gullow构建过程添加条件