Webpackで環境依存変数を渡す


306

Angularアプリをgulpからwebpackに変換しようとしています。gulpでは、gulp-preprocessを使用して、HTMLページのいくつかの変数(データベース名など)をNODE_ENVに応じて置き換えます。Webpackで同様の結果を得る最良の方法は何ですか?


1
エイリアスは役に立ちましたか?
JuhoVepsäläinen15年

1
@bebraw:エイリアスを理解する前に、DefinePlugin()に基づいて提案した他のソリューションを実装しました。エイリアスがより良い解決策であり、おそらくいつかリファクタリングされると私は今わかっています-ありがとう。2つのソリューションを回答に含めたい場合は、喜んで受け入れます。
kpg

2
コンソールメッセージを介してここに送信されました。Browserifyでこれを修正する方法?
GN。

2
この質問は、ビルド時またはロード時にSPAを構成しようとしていますか?SPAの構成には2つのタイプがあります。1)開発モードまたは本番モード、および2)デプロイメント環境(開発、ステージング、本番など)です。NODE_ENVはビルド時に(1)を構成するために使用できると思いますが、たとえば、さまざまなデプロイメント環境用にプロダクションモードを構成するなど、デプロイメント時に(2)を構成するにはどうすればよいでしょうか。これがこの質問に関連していることを願っています。
Ashley Aitken、2016

1
私はこのスレッドで答えを見つけることができませんでしたの@AshleyAitkenグレート質問(たぶん私はそれを逃した)が、この新しいスレッド投稿:stackoverflow.com/questions/44464504/...
デヴィッドTesar

回答:


427

これを達成するには、2つの基本的な方法があります。

DefinePlugin

new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),

これは一致を「そのまま」置き換えるだけであることに注意してください。これが、文字列の形式です。そこにあるオブジェクトのように、もっと複雑な構造にすることもできますが、アイデアはわかります。

EnvironmentPlugin

new webpack.EnvironmentPlugin(['NODE_ENV'])

EnvironmentPluginDefinePlugin内部的に使用し、それを介してコーディングするために環境値をマップします。Terser構文。

エイリアス

または、エイリアス化されたモジュールを介し構成を使用することもできます。消費者側からは、次のようになります。

var config = require('config');

構成自体は次のようになります。

resolve: {
    alias: {
        config: path.join(__dirname, 'config', process.env.NODE_ENV)
    }
}

レッツ・発言です。それはその時にマップされます。マップするモジュールは、次のように構成をエクスポートできます。process.env.NODE_ENVdevelopment./config/development.js

module.exports = {
    testing: 'something',
    ...
};

3
「現状のまま」で一致を置き換えるという事実を指摘していただきありがとうございます。私のコードがエラーをスローする理由を理解するのにしばらく苦労していました。これは、値をaにラップしていなかったためでしたJSON.stringify()
pbojinov

4
ES2015を使用している場合は、文字列補間も使用できます'process.env.NODE_ENV': `"${process.env.NODE_ENV || 'development'}"`
user2688473

1
@ tybro0103 JSON.stringify('development')は、実際には役に立たない可能性があります。代わりにJSON.stringify(someVariable)かなりすることができます!
superjos 2016

1
あなたNODE_ENVはそれを行うように設定する必要があります。設定方法はプラットフォームによって異なります。
JuhoVepsäläinen16年

1
@AnyulRivasうん。Reactはprocess.env.NODE_ENVパターンを使用しており、機能します。
JuhoVepsäläinen2017

109

もう1つのオプションとして、CLIインターフェイスのみを使用するdefine場合は、webpack のオプションを使用します。次のスクリプトをmyに追加しますpackage.json

"build-production": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"

したがって、実行する必要がありますnpm run build-production


2
これに関するドキュメントはありますか?私はグーグルできません--define :(
Richard

5
webpack @ 2の場合、「-p」はすでに--optimize-minimize --define process.env.NODE_ENV = "production"のショートカットです
okm

@okmドキュメントでは-p --optimize-minimize --optimize-occurence-orderと同じであるため、-define process.env.NODE_ENV = "production"については言及されていません。削除されたものですか?
Nader Ghanbari、2016年

1
@NaderHadjiGhanbariこれは、webpackバージョン2にありますwebpack.js.org/api/cli/#shortcuts
okm

73

私は環境固有の変数を設定する方法についていくつかのオプションを調査し、これで終わりました:

現在2つのwebpack設定があります:

webpack.production.config.js

new webpack.DefinePlugin({
  'process.env':{
    'NODE_ENV': JSON.stringify('production'),
    'API_URL': JSON.stringify('http://localhost:8080/bands')
  }
}),

webpack.config.js

new webpack.DefinePlugin({
  'process.env':{
    'NODE_ENV': JSON.stringify('development'),
    'API_URL': JSON.stringify('http://10.10.10.10:8080/bands')
  }
}),

私のコードでは、次の(簡単な)方法でAPI_URLの値を取得しています。

const apiUrl = process.env.API_URL;

2016年11月3日編集

Webpack docsに例があります:https ://webpack.js.org/plugins/define-plugin/#usage

new webpack.DefinePlugin({
    PRODUCTION: JSON.stringify(true),
    VERSION: JSON.stringify("5fa3b9"),
    BROWSER_SUPPORTS_HTML5: true,
    TWO: "1+1",
    "typeof window": JSON.stringify("object")
})

ではESLintお持ちの場合は、特にコード内の未定義の変数を許可する必要があるno-undef上でのルールを。http://eslint.org/docs/rules/no-undefこのように:

/*global TWO*/
console.log('Running App version ' + TWO);

2017年9月7日の編集(Create-React-App固有)

あまり設定しない場合は、Create-React-App:Create-React-App-Adding Custom Environment Variablesを確認してください。内部的には、CRAはとにかくWebpackを使用します。


2
これにより、実行時に環境変数が渡されないことがわかりましたか?全体を置き換えると、たとえば、webpackのビルド中に解決されprocess.envません。つまり、環境からポートを上書きできなくなりますか?process.env.PORTundefined
djskinner

本当にありがとう。最後に、わかりやすいこの問題の答えです。
Dave Sag、2016年

プロセスとは何ですか?どこから来たの?それがノードオブジェクトである場合、どのようにしてブラウザに入りますか?
Daniel Birowsky Popeski、2016年

これはひどい解決策です。NODE_ENVとAPI_URLの設定を除いて、ほぼ完全に同じ2つのwebpack.configsがあります
Brian Ogden

1
@BrianOgdenうん、確かに、これにはwebpack-mergeのようなものを使用する必要があります。npmjs.com/ package / webpack- merge-この質問のIMOには少し範囲外です。
伝道者

24

あなたは渡すことができます任意のコマンドライン引数を追加プラグインせずに使用して--envのWebPACK 2以降:

webpack --config webpack.config.js --env.foo=bar

webpack.config.jsで変数を使用:

module.exports = function(env) {
    if (env.foo === 'bar') {
        // do something
    }
}

ソース


22

EnvironmentPlugin利用可能な直接使用することができますwebpack変換中に任意の環境変数にアクセスできます。

webpack.config.jsファイルでプラグインを宣言する必要があります:

var webpack = require('webpack');

module.exports = {
    /* ... */
    plugins = [
        new webpack.EnvironmentPlugin(['NODE_ENV'])
    ]
};

使用する環境変数の名前を明示的に宣言する必要があることに注意してください。


4
この非常にユースケースのあるwebpack docsに例があります。github.com/webpack/docs/wiki/list-of-plugins#environmentplugin
Technetium

1
環境変数を.envファイルに配置する場合は、dotenvパッケージを使用して、webpack.config.jsで初期化できます。npmjs.com/package/dotenv
Justin McCandless

13

個人的に多数の回答に追加するには、次のようにします。

const webpack = require('webpack');
const prod = process.argv.indexOf('-p') !== -1;

module.exports = {
  ...
  plugins: [
    new webpack.DefinePlugin({
      process: {
        env: {
          NODE_ENV: prod? `"production"`: '"development"'
        }
      }
    }),
    ...
  ]
};

これを使用すると、ファンキーなenv変数やクロスプラットフォームの問題はありません(env varsを使用)。実行するのは、それぞれ通常webpackまたはwebpack -pdevまたは製品用です。

参照: Githubの問題


プロセスの値を定義するときは、を優先'process.env.NODE_ENV': JSON.stringify('production')process: { env: { NODE_ENV: JSON.stringify('production') } }ます。後者を使用すると、プロセスオブジェクトが上書きされ、プロセスオブジェクトの他の値が定義されることを期待する一部のモジュールとの互換性が失われる可能性があります。
slorenzo

13

伝道者による上記の投稿に対する私の編集が承認されなかったため、追加情報を投稿しました。

定義されたバージョン番号のようにpackage.jsonから値を選択し、JavaScript内のDefinePluginを介してそれにアクセスする場合。

{"version": "0.0.1"}

次に、インポートpackage.jsonそれぞれの内部webpack.configは、その後に属性を使用して、インポート変数を使用して属性にアクセスDefinePlugin

const PACKAGE = require('../package.json');
const _version = PACKAGE.version;//Picks the version number from package.json

たとえば、webpack.configの特定の構成は、DefinePluginに METADATAを使用しています。

const METADATA = webpackMerge(commonConfig({env: ENV}).metadata, {
  host: HOST,
  port: PORT,
  ENV: ENV,
  HMR: HMR,
  RELEASE_VERSION:_version//Version attribute retrieved from package.json
});

new DefinePlugin({
        'ENV': JSON.stringify(METADATA.ENV),
        'HMR': METADATA.HMR,
        'process.env': {
          'ENV': JSON.stringify(METADATA.ENV),
          'NODE_ENV': JSON.stringify(METADATA.ENV),
          'HMR': METADATA.HMR,
          'VERSION': JSON.stringify(METADATA.RELEASE_VERSION)//Setting it for the Scripts usage.
        }
      }),

typescriptファイル内でこれにアクセスします。

this.versionNumber = process.env.VERSION;

最も賢い方法は次のようになります:

// webpack.config.js
plugins: [
    new webpack.DefinePlugin({
      VERSION: JSON.stringify(require("./package.json").version)
    })
  ]

ロス・アレンのおかげで


11

@ zer0chainの回答と同様の別の回答です。ただし、1つの違いがあります。

設定webpack -pは十分です。

以下と同じです。

--define process.env.NODE_ENV="production"

そしてこれは同じです

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  //...

  plugins:[
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    })
  ]
};

したがって、package.jsonNodeファイルでは次のようなものだけが必要になる場合があります。

{
  "name": "projectname",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "debug": "webpack -d",
    "production": "webpack -p"
  },
  "author": "prosti",
  "license": "ISC",
  "dependencies": {    
    "webpack": "^2.2.1",
    ...
  }
}

DefinePluginからのいくつかのヒント:

DefinePluginを使用すると、コンパイル時に構成できるグローバル定数を作成できます。これは、開発ビルドとリリースビルドの間で異なる動作を許可する場合に役立ちます。たとえば、グローバル定数を使用して、ロギングが行われるかどうかを判断できます。おそらく、開発ビルドではロギングを実行しますが、リリースビルドでは実行しません。それは、DefinePluginが容易にするシナリオの一種です。


これは、入力したかどうかを確認できるようにするためです。 webpack --help

Config options:
  --config  Path to the config file
                         [string] [default: webpack.config.js or webpackfile.js]
  --env     Enviroment passed to the config, when it is a function

Basic options:
  --context    The root directory for resolving entry point and stats
                                       [string] [default: The current directory]
  --entry      The entry point                                          [string]
  --watch, -w  Watch the filesystem for changes                        [boolean]
  --debug      Switch loaders to debug mode                            [boolean]
  --devtool    Enable devtool for better debugging experience (Example:
               --devtool eval-cheap-module-source-map)                  [string]
  -d           shortcut for --debug --devtool eval-cheap-module-source-map
               --output-pathinfo                                       [boolean]
  -p           shortcut for --optimize-minimize --define
               process.env.NODE_ENV="production" 

                      [boolean]
  --progress   Print compilation progress in percentage                [boolean]

3

回答の束に追加するには:

DefinePluginの代わりにExtendedDefinePluginを使用する

npm install extended-define-webpack-plugin --save-dev.

ExtendedDefinePluginの方がはるかに使いやすく、文書化されています:-) リンク

DefinePluginに優れたドキュメントがないため、実際にはc#の#DEFINEのように機能すると言って、手助けしたいと思います。

#if (DEBUG)
        Console.WriteLine("Debugging is enabled.");
#endif

したがって、DefinePluginの仕組みを理解したい場合は、c##define doucmentationをお読みください。リンク


2

異なる環境では.envファイルを使用することを好みます。

  1. webpack.dev.configを使用してenv.dev、.envをルートフォルダーにコピーします。
  2. webpack.prod.configを使用して.envにコピーenv.prodします

そしてコードで

使用する

require('dotenv').config(); const API = process.env.API ## which will store the value from .env file


2

次の解決策は、Webpack 2の環境変数を設定するのが最も簡単であることがわかりました。

たとえば、webpack設定があります。

var webpack = require('webpack')

let webpackConfig = (env) => { // Passing envirmonment through
                                // function is important here
    return {
        entry: {
        // entries
        },

        output: {
        // outputs
        },

        plugins: [
        // plugins
        ],

        module: {
        // modules
        },

        resolve: {
        // resolves
        }

    }
};

module.exports = webpackConfig;

Webpackに環境変数を追加します。

plugins: [
    new webpack.EnvironmentPlugin({
       NODE_ENV: 'development',
       }),
]

プラグイン変数を定義し、次の場所に追加しpluginsます。

    new webpack.DefinePlugin({
        'NODE_ENV': JSON.stringify(env.NODE_ENV || 'development')
    }),

次に、webpackコマンドを実行するときにenv.NODE_ENV、引数として渡します。

webpack --env.NODE_ENV=development

// OR

webpack --env.NODE_ENV development

これNODE_ENVで、コードのどこからでも変数にアクセスできます。



1

これは私にとってうまくいき、jsonファイルを再利用することで環境変数をDRYに保つことができる方法です。

const webpack = require('webpack');
let config = require('./settings.json');
if (__PROD__) {
    config = require('./settings-prod.json');
}

const envVars = {};
Object.keys(config).forEach((key) => {
    envVars[key] = JSON.stringify(config[key]);
});

new webpack.DefinePlugin({
    'process.env': envVars
}),

0

私はあまり好きではありません...

new webpack.DefinePlugin({
  'process.env': envVars
}),

...これは、いかなるタイプのセキュリティも提供しないためです。その代わり、あなたはあなたの秘密のものを後押しすることになります、gitignoreにウェブパックを追加しない限り🤷‍♀️より良い解決策があります

基本的にこの構成では、コードをコンパイルすると、すべてのプロセス環境変数がコード全体から削除されtransform-inline-environment-variables ます。終了したくない場合は、BabelプラグインPSのおかげで単一のprocess.env.VAR はありません。 undefinesがたくさんある場合は、webpackがbabel-loaderを呼び出す前にenv.jsを呼び出してください。これが、webpackが最初に呼び出す理由です。babel.config.jsファイル内の変数の配列は、env.js上のオブジェクトと一致する必要があります。今やるべきことは、刈り取り作業が1つだけです。.envファイルを追加し、そこにすべての環境変数を配置します。ファイルはプロジェクトのルートにあるか、必要な場所に自由に追加する必要があります。env.jsファイルに同じ場所を設定し、それを追加してください。 gitignore

const dotFiles = ['.env'].filter(Boolean);

if (existsSync(dotFiles)) {
    require("dotenv-expand")(require("dotenv").config((dotFiles)));
}

全体のバベル+ Webpack + TSを表示したい場合は、heawから取得します https://github.com/EnetoJara/Node-typescript-babel-webpack.git

同じロジックが反応と他のすべてに適用されます💩

config
---webpack.js
---env.js
src
---source code world
.env
bunch of dotFiles

env.js

"use strict";
/***
I took the main idea from CRA, but mine is more cooler xD
*/
const {realpathSync, existsSync} = require('fs');
const {resolve, isAbsolute, delimiter} = require('path');

const NODE_ENV = process.env.NODE_ENV || "development";

const appDirectory = realpathSync(process.cwd());

if (typeof NODE_ENV !== "string") {
    throw new Error("falle and stuff");
}

const dotFiles = ['.env'].filter(Boolean);

if (existsSync(dotFiles)) {
    require("dotenv-expand")(require("dotenv").config((dotFiles)));
}

process.env.NODE_PATH = (process.env.NODE_PATH || "")
    .split(delimiter)
    .filter(folder => folder && isAbsolute(folder))
    .map(folder => resolve(appDirectory, folder))
    .join(delimiter);

const ENETO_APP = /^ENETO_APP_/i;

module.exports = (function () {
    const raw = Object.keys ( process.env )
        .filter ( key => ENETO_APP.test ( key ) )
        .reduce ( ( env, key ) => {
                env[ key ] = process.env[ key ];
                return env;
            },
            {
                BABEL_ENV: process.env.ENETO_APP_BABEL_ENV,
                ENETO_APP_DB_NAME: process.env.ENETO_APP_DB_NAME,
                ENETO_APP_DB_PASSWORD: process.env.ENETO_APP_DB_PASSWORD,
                ENETO_APP_DB_USER: process.env.ENETO_APP_DB_USER,
                GENERATE_SOURCEMAP: process.env.ENETO_APP_GENERATE_SOURCEMAP,
                NODE_ENV: process.env.ENETO_APP_NODE_ENV,
                PORT: process.env.ENETO_APP_PORT,
                PUBLIC_URL: "/"
            } );

    const stringyField = {
        "process.env": Object.keys(raw).reduce((env, key)=> {
            env[key]=JSON.stringify(raw[key]);
            return env;
        },{}),

    };

    return {
        raw, stringyField
    }
})();

プラグイントロールのないwebpackファイル

"use strict";

require("core-js");
require("./env.js");

const path = require("path");
const nodeExternals = require("webpack-node-externals");

module.exports = env => {
    return {
        devtool: "source-map",
        entry: path.join(__dirname, '../src/dev.ts'),
        externals: [nodeExternals()],
        module: {
            rules: [
                {
                    exclude: /node_modules/,
                    test: /\.ts$/,
                    use: [
                        {
                            loader: "babel-loader",
                        },
                        {
                            loader: "ts-loader"
                        }
                    ],
                },
                {
                    test: /\.(png|jpg|gif)$/,
                    use: [
                        {
                            loader: "file-loader",
                        },
                    ],
                },
            ],
        },
        node: {
            __dirname: false,
            __filename: false,
        },
        optimization: {
            splitChunks: {
                automaticNameDelimiter: "_",
                cacheGroups: {
                    vendor: {
                        chunks: "initial",
                        minChunks: 2,
                        name: "vendor",
                        test: /[\\/]node_modules[\\/]/,
                    },
                },
            },
        },
        output: {
            chunkFilename: "main.chunk.js",
            filename: "name-bundle.js",
            libraryTarget: "commonjs2",
        },
        plugins: [],
        resolve: {
            extensions: ['.ts', '.js']
        }   ,
        target: "node"
    };
};

babel.config.js

module.exports = api => {

    api.cache(() => process.env.NODE_ENV);

    return {

        plugins: [
            ["@babel/plugin-proposal-decorators", { legacy: true }],
            ["@babel/plugin-transform-classes", {loose: true}],
            ["@babel/plugin-external-helpers"],
            ["@babel/plugin-transform-runtime"],
            ["@babel/plugin-transform-modules-commonjs"],
            ["transform-member-expression-literals"],
            ["transform-property-literals"],
            ["@babel/plugin-transform-reserved-words"],
            ["@babel/plugin-transform-property-mutators"],
            ["@babel/plugin-transform-arrow-functions"],
            ["@babel/plugin-transform-block-scoped-functions"],
            [
                "@babel/plugin-transform-async-to-generator",
                {
                    method: "coroutine",
                    module: "bluebird",
                },
            ],
            ["@babel/plugin-proposal-async-generator-functions"],
            ["@babel/plugin-transform-block-scoping"],
            ["@babel/plugin-transform-computed-properties"],
            ["@babel/plugin-transform-destructuring"],
            ["@babel/plugin-transform-duplicate-keys"],
            ["@babel/plugin-transform-for-of"],
            ["@babel/plugin-transform-function-name"],
            ["@babel/plugin-transform-literals"],
            ["@babel/plugin-transform-object-super"],
            ["@babel/plugin-transform-shorthand-properties"],
            ["@babel/plugin-transform-spread"],
            ["@babel/plugin-transform-template-literals"],
            ["@babel/plugin-transform-exponentiation-operator"],
            ["@babel/plugin-proposal-object-rest-spread"],
            ["@babel/plugin-proposal-do-expressions"],
            ["@babel/plugin-proposal-export-default-from"],
            ["@babel/plugin-proposal-export-namespace-from"],
            ["@babel/plugin-proposal-logical-assignment-operators"],
            ["@babel/plugin-proposal-throw-expressions"],
            [
                "transform-inline-environment-variables",
                {
                    include: [
                        "ENETO_APP_PORT",
                        "ENETO_APP_NODE_ENV",
                        "ENETO_APP_BABEL_ENV",
                        "ENETO_APP_DB_NAME",
                        "ENETO_APP_DB_USER",
                        "ENETO_APP_DB_PASSWORD",
                    ],
                },
            ],
        ],
        presets: [["@babel/preset-env",{
            targets: {
                node: "current",
                esmodules: true
            },
            useBuiltIns: 'entry',
            corejs: 2,
            modules: "cjs"
        }],"@babel/preset-typescript"],
    };
};

「gitignoreにWebpackを追加しない限り、あなたはあなたの秘密のものを後押しすることになります。」@エルネストあなたはそれをさらに拡張できますか?
ケイティバイヤーズ

基本的に、あなたのバンドルはprocess.env.BLAHBLAHなしで終わり、実際の値を入れます。たとえば、process.env.NODE_ENVを「プロダクション」にしてしまう代わりに、これは最良の例ではなく、秘密鍵を想像してみてください。あなたのバンドルには実際の価値があり、そのワイヤードストリングが何を表すのか誰が知っていますか🤷‍♀️
Ernesto

うーん-はい、これらの値はビルドされたバージョンで補間されますが、おそらくそれをGitHubにプッシュしていません...
Katie Byers

-4

なぜなのかはわかりませんが、最も簡単な解決策については誰も触れていません。これは私にとってnodejsとgruntで機能します。多くの人にとって、webpackは混乱する可能性があるので、以下の行を使用するだけです:

process.env.NODE_ENV = 'production';

上記のソリューションでは、envifyやwebpackを使用する必要はありません。単純なハードコードされたソリューションが一部の人に役立つ場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.