【webpack】環境によってビルドする内容を分ける方法


jsのconfigファイルが本番環境と開発環境で違う場合があります。
しかしconfigファイルを含んだファイルをビルドする場合、phpのように.envで分けるみたいなことが出来ません。
そこで、本番環境用にビルドする時と、開発環境用にビルドする時でコマンドを分けることで、この問題が解消されます。

この分ける方法には大きく３つの方法があります。
状況に応じて使い分けていただければと思います。

## 独立した設定ファイルを作る方法
webpackはデフォルトではwebpack.config.jsというファイルに設定を定義します。
これを開発用と本番用でファイルを分けて別々に実行します。
例えば
開発用はwebpack.dev.js
本番用はwebpack.prod.js
で別々に作ります。
そしてビルドする時は
開発用なら`webpack --config webpack.dev.js`
本番用なら`webpack --config webpack.prod.js`
を実行します。

ちなみに
webpack.config.js

```js
module.exports = function(env) {
  return require('./webpack.${env}.js')
}
```
このようにして

```shell-session
webpack --env=dev
```
みたいな感じで分けられるようなことが[【公式ドキュメント】](https://webpack.js.org/guides/production/#simple-approach)書いてあったので試してみたが出来なかった。
出来た人居たら教えてください。


**独立した設定ファイルを作る方法**はシンプルで分かりやすいかと思います。
しかしデメリットとして、共通部分も２回編集しなければならなくなります。


## 環境変数を使って分ける方法
開発環境と本番環境で違いが少ない場合は環境変数を使って分ける方法が良いかと思います。

### nodeの環境変数を渡す方法
コマンド

```shell-session
NODE_ENV=production webpack
```
するとjs側で`process.env.NODE_ENV`という環境変数で取得することが出来ます。
なので変数によってif文で分けてあげれば良いだけです。
例えば本番と開発でentryするファイルを分けたい場合は以下のようにします。
webpack.config.js

```js
if (process.env.NODE_ENV === 'production') {
    console.log('production');
    var configfile = 'config.js';
}else{
    console.log('devlope');
    configfile = 'config-dev.js';
}
```
これで本番の時は`NODE_ENV=production webpack`を実行して、
それ以外のときは`webpack`と実行すればよいです。

参考
* [Node.jsでの環境変数の使い方](http://numb86-tech.hatenablog.com/entry/2017/01/24/000940)


## dotenvを使う方法
npmでdotenvをインストールします。
```
npm install dotenv --save
```
そうするとphpの.envと同じ要領で使う事ができます。
例
.env

```js
DB_HOST="localhost"
DB_USER="root"
```
config.js

```js
console.log(process.env.DB_HOST);
console.log(process.env.DB_USER);
```
こんな感じで。
どちらの環境でも`webpack`を実行出来る場合は、各環境で`webpack`を実行すればよい。
出来ない場合として本番がs3だったりとか...

参考
* [Nodeプロジェクトで環境依存の設定の管理方法](http://qiita.com/ueokande/items/80048f886082fea5b776)



## webpack-mergeを使う方法
これはテンプレートエンジンみたいな感じです。

共通部分をwebpack.common.jsに記述します。
本番のみの箇所をwebpack.prod.jsに記述してwebpack.common.jsをマージします。
開発のみの箇所をwebpack.dev.jsに記述してwebpack.common.jsをマージします。

例
webpack.common.js

```js

module.exports = {
    "entry": {
        ...
    },
    "output": {
        ...
    },
    module: {
        ...
    },
}
```
例
webpack.dev.js、webpack.prod.js

```js
const Merge = require('webpack-merge');
const CommonConfig = require('./webpack.common.js');

module.exports = Merge(CommonConfig, {
    "entry": {
        ...
    },
    "output": {
        ...
    },
    module: {
        ...
    },
}
```

実行するには

```shell-session
webpack --config webpack.dev.js
```

本番と開発で変える箇所が**まあまあ**あるときはこちらを使うと良いかと思います。

* [【公式ドキュメント】Production - Advanced Approach](https://webpack.js.org/guides/production/#advanced-approach)

* [webpackの設定ファイルを環境ごとに分けるには](http://qiita.com/takepo/items/fce9cd7b6742201cddc2)


## 【おまけ】DefinePluginを使って環境変数をモジュールに使う方法
webpack.config.jsのentryに書いているファイルがモジュールなのだが、そのモジュール内でも環境変数を使いたい場合にDefinePluginを使う。
使い方としては
webpack.config.js

```js
module.exports = {
    "entry": {
        ...
    },
    "output": {
        ...
    },
    module: {
        ...
    },
    plugins: [
        new webpack.DefinePlugin({
          NODE_ENV: JSON.stringify(process.env.NODE_ENV),
        })
    ]
}

```
みたいな感じで設定すればモジュールで

```js
console.log(PRODUCTION);
```
見ないな感じで取れるはず。
ちなみにDefinePluginは試して居ないので動かないかも

参考
* [Webpackを使ってJSでも.envしたい](http://qiita.com/mikakane/items/5ab96c4c7e187ab6c9f1)
* [webpackでReact/Reduxを本番環境用にビルド(production build)する](http://dackdive.hateblo.jp/entry/webpack-production-build)
* [【公式ドキュメント】DefinePlugin](https://webpack.js.org/plugins/define-plugin/)