Javascript 基于Webpack环境的条件构建
我有一些需要开发的东西,例如mock,我不想让它膨胀我的分布式构建文件 在RequireJS中,您可以在插件文件中传递一个配置文件,并根据该文件有条件地要求输入内容 对于webpack,似乎没有一种方法可以做到这一点。首先,要为环境创建运行时配置,我已使用该配置根据环境重新指向require,例如:Javascript 基于Webpack环境的条件构建,javascript,build,conditional,require,webpack,Javascript,Build,Conditional,Require,Webpack,我有一些需要开发的东西,例如mock,我不想让它膨胀我的分布式构建文件 在RequireJS中,您可以在插件文件中传递一个配置文件,并根据该文件有条件地要求输入内容 对于webpack,似乎没有一种方法可以做到这一点。首先,要为环境创建运行时配置,我已使用该配置根据环境重新指向require,例如: // All settings. var all = { fish: 'salmon' }; // `envsettings` is an alias resolved at build
// 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.
}
但是很明显,如果环境不是mock,我不想在这些mock文件中构建
我可以再次使用resolve.alias手动将所有这些要求重新指向存根文件,但有没有一种方法让我感觉不那么黑客
你知道我该怎么做吗?谢谢。您可以使用
我在网页包构建文件中使用它,其中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,它将从构建文件中删除此代码。您可以看到一个工作模式。另一种方法是使用JS文件作为代理,并让该文件在
commonjs
中加载感兴趣的模块,并将其导出为es2015模块,如下所示:
// 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"
//myApp.js
从“./store/myModule.js”导入{myString}
myString/我最终使用了类似的东西,但担心两点:
每次使用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
,它使用生成一个环境变量\uuuu APP\u config\uuuu
,该变量保存组合的配置对象:
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导入导出语法,因为它位于网页包下):
在你的app.js
中,你现在可以使用importconfig from./config'
获取配置对象。使用。在源文件中,您可以执行以下操作
/// #if ENV === 'production'
console.log('production!');
/// #endif
相关的网页
配置为
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}`,
},
},
],
},
// ...
};
不确定为什么“webpack.DefinePlugin”答案是定义基于环境的导入/需求的首选答案
这种方法的问题是,您仍然在向客户机交付所有这些模块,例如->检查。并且根本不减少bundle.js的大小:)
因此,真正有效且更符合逻辑的是:
因此,与其执行on_client conditional require->首先不要将不需要的文件包含到包中
希望这会有所帮助虽然这不是最好的解决方案,但它可能会满足您的一些需求。如果要在节点和浏览器中运行不同的代码,请使用此选项:
if (typeof window !== 'undefined')
return
}
//run node only code now
使用环境变量创建开发和产品部署:
我一直在努力在我的网页配置中设置env。我通常希望设置env,以便在webpack.config.js
、postsss.config.js
和入口点应用程序本身(index.js
通常)中可以访问它。我希望我的发现能帮助别人
我提出的解决方案是传入--env production
或--env development
,然后在webpack.config.js
中设置模式。
但是,这并不能帮助我在需要的地方访问env
(见上文),因此我还需要按照建议显式设置process.env.NODE\u env
。
下面是我在webpack.config.js
中看到的最相关的部分
。。。
module.exports=模式=>{
process.env.NODE_env=模式;
如果(模式=“生产”){
返回merge(commonConfig,productionConfig,{mode});
}
返回合并(commonConfig,developmentConfig,{mode});
};
面临着与OP相同的问题,并且由于许可,在某些版本中不包含某些代码,我采用了如下方法:
在build命令中,我为构建设置了一个适当的环境变量。例如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中删除。例如,在my 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。请注意,目前我已使用alias在我不想要的环境中指向一个空(存根)文件(例如,require('mocks'))将指向非模拟环境上的一个空文件。似乎有点黑客,但它可以工作。if/else和require的唯一问题是,两个必需的文件都将绑定到生成的文件中。我还没有找到解决方法。基本上,绑定首先发生,然后损坏。如果您在网页包文件中使用插件w,则不一定如此ebpack.optimize.UglifyJsPlugin()
,网页的优化不会加载模块,a
...
// #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
...