简体   繁体   English

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

[英]Conditional build based on environment using Webpack

I have some things for development - eg mocks which I would like to not bloat my distributed build file with. 我有一些需要开发的东西 - 例如我想不会破坏我的分布式构建文件的模拟。

In RequireJS you can pass a config in a plugin file and conditonally require things in based on that. 在RequireJS中,您可以在插件文件中传递配置,并根据需要调整其中的内容。

For webpack there doesn't seem to be a way of doing this. 对于webpack,似乎没有办法做到这一点。 Firstly to create a runtime config for an environment I have used resolve.alias to repoint a require depending on the environment, eg: 首先创建一个环境中运行时配置我用resolve.alias重新指向一个取决于环境,例如,需要:

// All settings.
var all = {
    fish: 'salmon'
};

// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require('envsettings'));

Then when creating the webpack config I can dynamically assign which file envsettings points to (ie webpackConfig.resolve.alias.envsettings = './' + env ). 然后在创建webpack配置时,我可以动态分配envsettings指向的文件(即webpackConfig.resolve.alias.envsettings = './' + env )。

However I would like to do something like: 不过我想做的事情如下:

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

But obviously I don't want to build in those mock files if the environment isn't mock. 但显然我不想在环境不是模拟的情况下构建那些模拟文件。

I could possibly manually repoint all those requires to a stub file using resolve.alias again - but is there a way that feels less hacky? 我可以再次使用resolve.alias手动将所有这些需求重新命名为存根文件 - 但是有没有一种感觉不那么hacky的方法?

Any ideas how I can do that? 我有什么想法可以做到这一点? Thanks. 谢谢。

You can use the define plugin . 您可以使用define插件

I use it by doing something as simple as this in your webpack build file where env is the path to a file that exports an object of settings: 我通过在你的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 };

and then this in your code 然后在你的代码中

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

It will strip this code out of your build file if the condition is false. 如果条件为false,它将从构建文件中删除此代码。 You can see a working Webpack build example here . 您可以在此处查看有效的Webpack构建示例

Not sure why the "webpack.DefinePlugin" answer is the top one everywhere for defining Environment based imports/requires. 不知道为什么“webpack.DefinePlugin”答案是定义基于环境的导入/需求的最顶层的答案。

The problem with that approach is that you are still delivering all those modules to the client -> check with webpack-bundle-analyezer for instance. 这种方法的问题在于您仍然将所有这些模块交付给客户端 - >例如,使用webpack-bundle-analyezer进行检查。 And not reducing your bundle.js's size at all :) 并没有减少你的bundle.js的大小:)

So what really works well and much more logical is: NormalModuleReplacementPlugin 那么真正运作良好且更符合逻辑的是: NormalModuleReplacementPlugin

So rather than do a on_client conditional require -> just not include not needed files to the bundle in the first place 因此,而不是做一个on_client条件要求 - >首先不要包含不需要的文件到bundle

Hope that helps 希望有所帮助

Use ifdef-loader . 使用ifdef-loader In your source files you can do stuff like 在您的源文件中,您可以执行类似的操作

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

The relevant webpack configuration is 相关的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}`,
        },
      },
    ],
  },
  // ...
};

I ended up using something similar to Matt Derrick' Answer , but was worried about two points: 我最终使用类似于Matt Derrick'Answer的东西,但担心两点:

  1. The complete config is injected every time I use ENV (Which is bad for large configs). 每次使用ENV时都会注入完整的配置(这对于大型配置是不好的)。
  2. I have to define multiple entry points because require(env) points to different files. 我必须定义多个入口点,因为require(env)指向不同的文件。

What I came up with is a simple composer which builds a config object and injects it to a config module. 我想出的是一个简单的作曲家,它构建一个配置对象并将其注入配置模块。
Here is the file structure, Iam using for this: 这是文件结构,Iam用于此:

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

The main.js holds all default config stuff: main.js包含所有默认配置内容:

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

module.exports = mainConfig;

The dev.js and production.js only hold config stuff which overrides the main config: dev.jsproduction.js只保存覆盖主配置的配置内容:

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

module.exports = devConfig;

The important part is the webpack.config.js which composes the config and uses the DefinePlugin to generate a environment variable __APP_CONFIG__ which holds the composed config object: 重要的部分是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))
    })
  ]
};

The last step is now the config.js , it looks like this (Using es6 import export syntax here because its under webpack): 最后一步是config.js ,它看起来像这样(在这里使用es6 import export语法,因为它在webpack下):

const config = __APP_CONFIG__;

export default config;

In your app.js you could now use import config from './config'; 在你的app.js你现在可以使用import config from './config'; to get the config object. 获取配置对象。

another way is using a JS file as a proxy , and let that file load the module of interest in commonjs , and export it as es2015 module , like this: 另一种方法是使用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

Then you can use ES2015 module in your app normally: 然后您可以在您的应用中正常使用ES2015模块:

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

Faced with the same problem as the OP and required, because of licensing, not to include certain code in certain builds, I adopted the webpack-conditional-loader as follows: 面对与OP相同的问题并且由于许可,不在某些构建中包含某些代码,我采用了webpack-conditional-loader ,如下所示:

In my build command I set an environment variable appropriately for my build. 在我的构建命令中,我为我的构建适当地设置了一个环境变量。 For example 'demo' in package.json: 例如package.json中的'demo':

...
  "scripts": {
    ...
    "buildDemo": "./node_modules/.bin/webpack --config webpack.config/demo.js --env.demo --progress --colors",
...

The confusing bit that is missing from the documentation I read is that I have to make this visible throughout the build processing by ensuring my env variable gets injected into the process global thus in my webpack.config/demo.js: 我读到的文档中遗漏的令人困惑的一点是, 我必须通过确保将我的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};

With this in place, I can conditionally exclude anything, ensuring that any related code is properly shaken out of the resulting JavaScript. 有了这个,我可以有条件地排除任何东西,确保任何相关的代码被正确地从生成的JavaScript中甩掉。 For example in my routes.js the demo content is kept out of other builds thus: 例如,在我的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
...

This works with webpack 4.29.6. 这适用于webpack 4.29.6。

I've struggled with setting env in my webpack configs. 我一直在努力在我的webpack配置中设置env。 What I usually want is to set env so that it can be reached inside webpack.config.js , postcss.config.js and inside the entry point application itself ( index.js usually). 我通常想要的是设置env,以便可以在webpack.config.jspostcss.config.js和入口点应用程序本身(通常是index.js )内部访问它。 I hope that my findings can help someone. 我希望我的发现可以帮助某人。

The solution that I've come up with is to pass in --env production or --env development , and then set mode inside webpack.config.js . 我提出的解决方案是传入--env production--env development ,然后在webpack.config.js设置模式。 However, that doesn't help me with making env accessible where I want it (see above), so I also need to set process.env.NODE_ENV explicitly, as recommended here . 然而,这并不能帮助我,使env ,我想它(见上文),所以我还需要设置访问process.env.NODE_ENV明确,建议在这里 Most relevant part that I have in webpack.config.js follow below. 我在webpack.config.js最相关的部分如下。

...
module.exports = mode => {
  process.env.NODE_ENV = mode;

  if (mode === "production") {
    return merge(commonConfig, productionConfig, { mode });
  }
  return merge(commonConfig, developmentConfig, { mode });
};

While this is not the best solution, it may work for some of your needs. 虽然这不是最佳解决方案,但它可能适合您的一些需求。 If you want to run different code in node and browser using this worked for me: 如果你想在节点和浏览器中运行不同的代码使用这对我有用:

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

Use envirnment variables to create dev and prod deployments: 使用环境变量来创建dev和prod部署:

https://webpack.js.org/guides/environment-variables/ https://webpack.js.org/guides/environment-variables/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM