webpack.config.jsのなかでビルド環境を調べる方法

# この記事について ✍️

あるプロジェクトでビルドツールとして **webpack** を利用していて、
そのプロジェクトで外部ツールを使って利用率を計測をしようとしました。

その外部ツールは本番用と開発用でAPIKeyが違いまして、
webpackの設定ファイルでビルド環境ごとに変数を出し分ける方法を調べるのにすこし手間取りまして。。

この記事の後半では `「webpackでビルド環境を調べ、環境変数を宣言する方法」` をサクッとご紹介するので時間がない方はそちらを！

前半部分では、なぜビルド環境をwebpackで調べたかったのか説明します。

# 環境 🤖

この記事では `webpack v4.27.1` と `webpack-cli v3.1.2` を使っています

# 前半： なぜビルド環境をwebpackで調べたかったのか

外部の分析ツール(Google Analytics的な)を使いたかったのですが、
本番環境と開発環境で分析を分けたかったんですよね。

その分析ツールをつかうにはAPIKeyが必要でして、
本番環境と開発環境で分析結果を分けるには、環境ごとにKeyを持っておく必要がありました。

ということは、例えばこんなイメージのコードができあがりそうです。

```index.js
import {logging} from "some_external_service"

if (environment === "production") {
  logging("本番用APIKey")
}
else if (environment === "development") {
  logging("開発用APIKey")
}
```

まず２点微妙な点があります

1. ビルドされた環境とは関係ない方のAPIKeyもソースコードに書いておく必要がある
2. APIKeyが変わったときにわざわざソースコードを修正する必要がある

**1** に関しては、ビルド環境ごとにAPIKeyを選べれば、関係ないAPIKeyをソースコードに存在させる必要がなくなります。
**2** に関しては、変数としてどこかに置いておけば、APIKeyがいつか変わってもソースコードは修正せずにすみます。

**となると**

`1. webpackでビルドするときに必要な方のAPIKeyだけを持っておいて、`
`2. それをソースコードから呼べるよう環境変数に持っておく`

しかないんですよね。（もっといい方法あったら教えてください！🙇‍♂️）

ということは、設定ファイルである `webpack.config.js` のなかで上記 **1** と **2** をやる必要が出てきます。
（コマンドラインで読み込む設定ファイルを指定する方法もありますが、今回はその方法には触れません）

後半部分では、どうやれば実現できるか紹介します！

# 後半： webpackでビルド環境を調べ、環境変数を宣言する方法

## １. webpack.config.jsのなかでビルド環境を調べる方法

そもそも、ビルド環境を調べる前に環境を指定する必要がありますね。

### 1. ビルド環境を指定する

2つ方法があります

#### 1. modeを設定する方法

webpack.config.jsに直接書き込む方法があります。

```webpack.config.js
module.exports = {
  mode: 'production'
};
```

ただ今回は **１つの設定ファイル** でやりたいので、上のやり方よりもwebpackCLIを使って`modeフラグ`を渡す方法が向いてます。

```package.json
  "scripts": {
    "build_prod": "webpack --mode=production",
    "build_dev": "webpack --mode=development"
  },
```

modeは、 `production` と `development` の二つの選択肢があります。

modeを使うメリットは、webpackによって勝手にビルドが最適化される点です。productionだとminifyとかしてくれます。

一方、modeより指定方法が豊富というか、そもそも趣旨がちょっと違う指定方法があります。それが、 `envフラグ`です。

#### 2. envを指定する方法

こちらは設定ファイルで指定する方法はなく、webpackCLIを使って`envフラグ`を渡します。

```package.json
  "scripts": {
    "build_prod": "webpack --env.production --environment=honban",
    "build_dev": "webpack --env.development "
  },
```

変数を宣言する感じですが、シンタックスシュガー的な書き方ができて、

例えば上の `--env.production` は、 webpack.config.js で受け取るときには
productionの中身は **true** というbooleanになります。

上の `--env.development` の中身は "develop" という文字列になります。

文字列を直接指定することもできて、 `--environment=honban` のenvironmentの中身は "honban" という文字列になります。

指定方法はたくさんありますが、詳しくは **[こちら](https://webpack.js.org/api/cli/#environment-options)** に書いてあります！

さてここまでは環境を指定する方法を書きましたが、次はビルド環境を調べる方法をご紹介します！

### 2. ビルド環境を調べる

`modeフラグ` と `envフラグ` でビルド環境を指定しましたが、それぞれ受け取り方が違います。

modeもenvも一気にご紹介します。

```package.json
  "scripts": {
    "build_prod": "webpack --env.production --environment=honban --mode=production",
  },
```

```webpack.config.js
// 第一引数にはenvフラグで指定した変数が入ってくる
// 第二引数には指定したmodeとか色々入ってくるが、今回はmodeだけ取り出す
module.exports = (env, {mode}) => ({ 
  console.log(env.production)  // true
  console.log(env.environment) // "honban"
  console.log(mode)            // "production"
  ...
});
```

このような感じで、 `module.exports` にオブジェクト自体ではなく **オブジェクトを返す関数** を渡します。
webpack内部では、この関数に引数を与えて実行するようになっているんですね。

さて、 webpack.config.js のなかでビルド環境が調べられたところで、
最後に環境変数を宣言する方法をご紹介します。

## 2. webpack.config.jsのなかで環境変数を宣言する方法

webpackが提供する `DefinePlugin` を利用します

```webpack.config.js
module.exports = (env, {mode}) => ({ 
  plugins: [
    new webpack.DefinePlugin({
      API_KEY:
        env.environment === "honban"
          ? JSON.stringify("本番用APIKey")
          : JSON.stringify("開発用APIKey")
    })
  ]
  ...
});
```

```index.js
import {logging} from "some_external_service"

logging(API_KEY)
```

## 最後に

今回は **webpackでビルド環境を調べ、環境変数を宣言する方法** をご紹介しました。

たくさんのビルド環境を使い分けなければならないプロダクトで、
さらに設定ファイルを環境の数だけ用意したくないという場合にとても有効な方法だと思います。

もっとスマートなやり方があったら教えてください、それでは良いお年を！