WebpackのDefinePluginが何かと便利そうだったので、node-env-file
との活用を考えてみました。
DefinePlugin
var webpack = require("webpack")
var loadenv = require("node-env-file")
module.exports = {
"entry": "...",
"output": "...",
module: {
// loaderの設定
},
plugins: [
new webpack.DefinePlugin({
//ココに定義を書いていく...
})
]
}
DefinePluginは、webpack.config.js内からモジュールに対し、設定値等の値を注入できるプラグインです。
APIのエントリURLや、各種設定値、環境値等を埋め込むことで、同一のコードを用いながらアプリケーションの挙動をビルド環境に合わせて多様化できます。
概要
次のようにして利用します。
new webpack.DefinePlugin({
API_KEY: JSON.stringify("KEY:XXX-XXX"),
})
console.log(API_KEY) // KEY:XXX-XXX
DefinePluginの引数で渡されたオブジェクトのキーと一致する値がビルド時に自動的に評価された値へと置き換えられます。
グローバル空間を汚染するわけでもなく、モジュールとしてコールできるようにナルわけでもありません。
単純にビルド時に結果が置き換えられているだけです。
(コンパイル後のコードを見るとわかりやすいかもです。)
注意が必要なのが、文字列やオブジェクトなどの値を割り当てるのに、JSON.stringify
を利用する必要があるということです。
これもコンパイル後のコードを見てもらうのが一番わかりやすいのですが、文字列を渡してもコンパイル後のコードは""
が無い状態で生成されるため、実行時エラーとなってしまいます。
node-env-fileとの連携
nodeでPHPやRubyなどでお馴染みの.env
を利用するライブラリとして、
node-env-file
というライブラリがあります。
https://www.npmjs.com/package/node-env-file
これをDefinePluginで使う際の構成について考えてみます。
var loadenv = require("node-env-file")
new webpack.DefinePlugin({
env:function(){
loadenv("./.env")
return JSON.stringify(process.env)
}
})
上記のような構成で行けるだろう…と思っていたのですが、結果はダメでした。
文字列を直接渡した時同様、functionのtoStringが直接埋め込まれるだけです。
そこで、下記のように即時関数として実行させて評価するという手法を取るとうまいこと行きました。
var loadenv = require("node-env-file)
new webpack.DefinePlugin({
env:(function(){
loadenv("./.env")
return JSON.stringify(process.env);
})()
})
ただこの状態だと、全ての環境変数がコンパイルされたコードに埋め込まれ、セキュリティ的に非常に危険です。
結果として次のような形に落ち着きました。
var loadenv = require("node-env-file)
new webpack.DefinePlugin({
env:(function(){
loadenv("./.env")
return JSON.stringify({
"APP_ENV": process.env.APP_ENV,
"APP_DEBUG": process.env.APP_DEBUG
});
})(),
})
いちいち列挙していくのはめんどくさいので、何かいい方法が無いものか画策中です。
オススメの方法とかあればコメントとか頂けると助かります。
ちなみに今回は、node-env-file
の活用が最終的な目標だったのでこういう形になりましたが、
そういうニーズがアルわけでも無ければ、ProvidePlugin
を使って環境ごとに注入モジュールを用意し、ビルド時に切り替える、みたいな方法もありです。ご参考まで
参考:Webpackプラグイン一覧
http://webpack.github.io/docs/list-of-plugins.html