我有一些需要开发的东西 - 例如我想不会破坏我的分布式构建文件的模拟。
在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手动将所有这些需求重新命名为存根文件 - 但有没有办法感觉不那么黑客?
我有什么想法可以做到这一点?感谢。
答案 0 :(得分:53)
您可以使用define plugin。
我通过在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 build example here。
答案 1 :(得分:31)
不确定为什么“webpack.DefinePlugin”答案是定义基于环境的导入/需要的最顶层答案。
使用该方法的问题是您仍然将所有这些模块提供给客户端 - >例如,请查看webpack-bundle-analyezer。而不是减少你的bundle.js的大小:)那么真正有效且更符合逻辑的是:NormalModuleReplacementPlugin
因此,而不是做一个on_client条件要求 - >首先不要在包中包含不需要的文件
希望有所帮助
答案 2 :(得分:22)
使用Link to Api Page。在源文件中,您可以执行
之类的操作/// #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}`,
},
},
],
},
// ...
};
答案 3 :(得分:19)
另一种方法是将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"
答案 4 :(得分:19)
我最终使用类似于Matt Derrick' Answer的东西,但担心有两点:
ENV
时都会注入完整的配置(这对大型配置不利)。require(env)
指向不同的文件。我想出的是一个简单的作曲家,它构建一个配置对象并将其注入配置模块 这是文件结构,Iam用于此:
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;
重要的部分是组成配置的webpack.config.js
,并使用DefinePlugin生成一个环境变量__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';
来获取配置对象。
答案 5 :(得分:2)
面对与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中剔除。例如,在我的routes.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。
答案 6 :(得分:0)
虽然这不是最佳解决方案,但它可能适合您的一些需求。如果你想在节点和浏览器中运行不同的代码使用这对我有用:
if (typeof window !== 'undefined')
return
}
//run node only code now
答案 7 :(得分:0)
使用环境变量创建开发和prod部署:
答案 8 :(得分:0)
我一直在努力在Webpack配置中设置env。我通常想要设置env,以便可以在webpack.config.js
,postcss.config.js
内部和入口点应用程序本身(通常为index.js
)内部访问它。我希望我的发现可以对某人有所帮助。
我想出的解决方案是传入--env production
或-- env development
,然后在webpack.config.js
内设置模式。
但是,这对我无法在需要的地方访问env
有所帮助(请参见上文),因此,我还需要按照建议的here显式设置process.env.NODE_ENV
。
我用分支working
和not_working
创建了一个最小的仓库。正如在not_working
中所确认的那样,使用webpack.DefinePlugin
将process.env.NODE_ENV
设置为记录的here并没有达到预期的效果。
来自repo的webpack.config.js中最相关的部分如下。
...
module.exports = mode => {
process.env.NODE_ENV = mode;
if (mode === "production") {
return merge(commonConfig, productionConfig, { mode });
}
return merge(commonConfig, developmentConfig, { mode });
};