簡體   English   中英

使用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手動將所有這些需求重新命名為存根文件 - 但是有沒有一種感覺不那么hacky的方法?

我有什么想法可以做到這一點? 謝謝。

您可以使用define插件

我通過在你的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進行檢查。 並沒有減少你的bundle.js的大小:)

那么真正運作良好且更符合邏輯的是: NormalModuleReplacementPlugin

因此,而不是做一個on_client條件要求 - >首先不要包含不需要的文件到bundle

希望有所幫助

使用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'Answer的東西,但擔心兩點:

  1. 每次使用ENV時都會注入完整的配置(這對於大型配置是不好的)。
  2. 我必須定義多個入口點,因為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.jsproduction.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 import export語法,因為它在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中甩掉。 例如,在我的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。

我一直在努力在我的webpack配置中設置env。 我通常想要的是設置env,以便可以在webpack.config.jspostcss.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 });
};

雖然這不是最佳解決方案,但它可能適合您的一些需求。 如果你想在節點和瀏覽器中運行不同的代碼使用這對我有用:

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

使用環境變量來創建dev和prod部署:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM