better-npm-run を使って OS に依存せず npm run-script に環境変数を渡す

前回の記事で、$ 環境変数=値 npm run スクリプト名 という書きで npm-scripts を呼ぶと、呼んだスクリプト内で process.env.環境変数 が参照できるようになる、という話をした。

しかしこの書き方は、Mac や Linux でしか上手く動かず、Windows では正しく動作しない。これはどうやら、npm run-scripts の内部処理で、Bash から呼ばれることを前提とした処理の仕方をしているせいのようで、利用者としてはどうこうできない部分みたい。

そこで、OS に依存せず、環境変数を渡してスクリプトを実行できるようになる、better-npm-run という npm パッケージを使ってみようと思う。

インストール方法

インストール方法は通常の npm パッケージと同じ。

# package.json に開発時に依存するパッケージとして追記しつつインストールする
$ npm install better-npm-run --save-dev
# 省略して書くと「npm i better-npm-run -D」

package.json の修正

次に、package.json を書き換え、better-npm-run を使うようにしていく。

例えば元の package.json が以下のようになっている場合。

{
  "scripts": {
    "build:js:dev": "DEV_MODE=true npm run gulp build:js",
    "build:js:product": "DEV_MODE=false npm run gulp build:js"
  }
}

2つのスクリプトは、DEV_MODE という環境変数の値をそれぞれ指定して、Gulp の build:js というタスクを実行しようとしている。

これを以下のようにする。

{
  "scripts": {
    "build:js:dev": "better-npm-run build:js:dev",
    "build:js:product": "better-npm-run build:js:product"
  },
  "betterScripts": {
    "build:js:dev": {
      "env": {
        "DEV_MODE": "true"
      },
      "command": "npm run gulp build:js"
    },
    "build:js:product": {
      "env": {
        "DEV_MODE": "false"
      },
      "command": "npm run gulp build:js"
    }
  }
}

解説

さて、何やら複雑化したような気がするが、OS 依存を回避するためには致し方ないことである。ざっくり何がどう変わったのか見てみよう。

まず元々の package.json の場合の流れを確認。

  1. npm run build:js:dev と叩いた場合。
  2. package.json の定義より、環境変数 DEV_MODEtrue を設定した上で、gulp build:js を呼び出す。

次に、修正後の流れがどうなったかというと。

  1. npm run build:js:dev と叩いた場合。
  2. package.json の定義より、better-npm-run で定義した build:js:dev スクリプトを実行する。
  3. better-npm-run のスクリプト定義は同じ package.jsonbetterScripts 内に定義されており、これを見ると、build:js:dev というタスクでは、環境変数 DEV_MODEtrue を設定した上で、npm run gulp build:js を呼び出している。

とまぁ、better-npm-run が挟まって、環境変数の受け渡しをうまくやってくれるようになった、というワケである。

npm run-scripts の利用者が該当タスク内で使用できる環境変数とその値を覚えておかなくて良くなるし、通常の "scripts" 内に書かれるよりも環境変数の可読性が高まるというメリットがある。

クロスプラットフォームで複雑なタスクを定義しているプロジェクトにおいては有用だと思うので、参考にしていただきたい。