web-dev-qa-db-ja.com

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を使用して、これらの必要なものすべてをスタブファイルに手動で再ポイントすることもできますが、ハッキングを軽減する方法はありますか?

私はそれをどのように行うことができますか?ありがとう。

79
Dominic

define plugin を使用できます。

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!');
}

条件が偽の場合、ビルドファイルからこのコードが削除されます。 Webpackビルドの例 が機能していることがわかります。

54
Matt Derrick

「webpack.DefinePlugin」の回答が、環境ベースのインポート/要件を定義するためのどこでも一番上の理由である理由はわかりません。

そのアプローチの問題は、それらのすべてのモジュールをまだクライアントに配信していることです-> webpack-bundle-analyezer で確認してください=たとえば。そして、bundle.jsのサイズをまったく縮小しません:)

したがって、実際にうまく機能し、はるかに論理的なものは次のとおりです。 NormalModuleReplacementPlugin

したがって、on_client条件付きrequireを実行するのではなく、最初にバンドルに不要なファイルを含めないでください。

役立つことを願っています

33
Roman Zhyliov

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}`,
        },
      },
    ],
  },
  // ...
};
25
Brynn Mahsman

Matt Derrick 'Answer に似たものを使用することになりましたが、2つのポイントが心配でした。

  1. ENVを使用するたびに、完全な構成が挿入されます(大規模な構成には不適切です)。
  2. require(env)は異なるファイルを指すため、複数のエントリポイントを定義する必要があります。

私が思いついたのは、簡単なcomposerです。これは、構成オブジェクトを構築し、それを構成モジュールに注入します。
これは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;

重要な部分は、構成を構成し、 DefinePlugin を使用して、構成された構成オブジェクトを保持する環境変数webpack.config.jsを生成する__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になり、次のようになります(webpackの下にあるため、ここでes6 import export構文を使用します):

const config = __APP_CONFIG__;

export default config;

app.jsimport config from './config';を使用して設定オブジェクトを取得できます。

21
ofhouse

別の方法は、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"
18
Alejandro Silva

OPと同じ問題に直面し、特定のビルドに特定のコードを含めないようにするために、ライセンスが必要なため、次のように webpack-conditional-loader を採用しました。

ビルドコマンドで、ビルドに適した環境変数を設定します。たとえば、package.jsonの「demo」:

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

私が読んだドキュメントにない紛らわしい部分は、ビルド処理全体でこれを見えるようにしなければならないということです私の環境変数がプロセスグローバルにインジェクトされるようにすることで、したがって私のウェブパックで.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で動作します。

3
Paul Whipp

Webpackの設定でenvを設定するのに苦労しました。たいていenvを設定して、webpack.config.jspostcss.config.js内およびエントリポイントアプリケーション自体(index.js内)に到達できるようにします。私の調査結果が誰かを助けることを願っています。

私が思いついた解決策は、--env productionまたは--env developmentを渡してから、webpack.config.js内でモードを設定することです。ただし、envを必要な場所にアクセスできるようにするのには役立ちません(上記参照)。したがって、推奨されるようにprocess.env.NODE_ENVを明示的に設定する必要があります herewebpack.config.jsにある最も関連性の高い部分は以下のとおりです。

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

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

これは最善の解決策ではありませんが、一部のニーズには役立つ場合があります。これを使用してノードとブラウザで別のコードを実行したい場合は私のために働いた:

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

環境変数を使用して、devおよびprodデプロイメントを作成します。

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

0
Simon H