(初稿: 2020.02.27)

前提

  • env-cmd を用いる理由は、利便性より安全性、可読性を重視した結果である
    • by Yuki Takei
  • Slack のログは Inner Wiki に残っている

代替候補とモチベーション

env-cmd を使う理由

1. npm/yarn の事情

  • npm/yarn のパッケージ管理は dependencies と devDependencies に分かれている
    • 逆に言えば、この2カテゴリにしか分けられない

上記制約により、例えば以下のようなケースで困る

  • GROWI(本体)で、クライアントビルドした後、サーバー用途のパッケージに絞ってから docker build したい
    • 素直に考えればサーバー用途のパッケージを dependencies に、クライアントビルドでしか使わないパッケージを devDependencies にリストする
    • CI で、本番用イメージを以下の手順でビルドする
      1. devDependencies 込みでインストール
      2. クライアントビルド (NODE_ENV=production にしたい)
      3. dependencies に絞る
      4. docker build (NODE_ENV=production にしたい)

env-cmd を利用しないケースでは、1-4の実行は、NODE_ENV を注意深く選択しないといけない。そしてそれは package.json によって固定化されることなく、各 CI ツールに登録されたスクリプトや、Heroku 等の PaaS で設定を誤らないことが期待される。これは安全ではない

参考: Heroku での不自然な NODE_ENV=development 設定

https://dashboard.heroku.com/new?template=https%3A%2F%2Fgithub.com%2Fweseek%2Fgrowi external_link

2. 過去の教訓から

node 系はロガーが貧弱なので、GROWI, GROWI.cloud では自作したことも。

イマドキの JavaScript 開発で使える、リモートデバッグとロガーの Tips (2018年版-後編) external_link

この時 NODE_ENV の値に応じて挙動を変えるというごく一般的な処理を書いたが、その際ある env 環境下で、別の env の設定を読み込んでしまうようなコードを書いてしまった(エンバグした)ことがある。

現況と元凶

Rails や Spring Boot は業界のデファクトのフレームワークであるが、これらは「環境を分けてコンフィグを書き分ける」機能をデフォルトで提供すると共に、タスクランナーも提供している。つまり、「環境を分けてコンフィグを読み分けられるタスクランナー」がデフォルトで提供されている。そこが強みであり、node 界隈に無い特徴である。

対して node 界隈では疲弊を経験した grunt/gulp 時代を経て今や package.json の scripts (npm コマンドで実行)が「タスクランナーの代替のデファクト」になっており(揺り返しでシンプルイズベストに振れすぎてしまった)、
また業界でデファクトである Express や Webpack には「環境を分けてコンフィグを読み分ける」機能は付いてこない。

node-config は確かに「環境を分けてコンフィグを書き分ける」機能を提供してくれるものだが、 gradle testgradle package のように env とそれに付随する設定ファイルを忖度して読み分けてくれるわけではなく、結局はそのハンドリングはプロジェクト管理者と自らのコードベースに委ねられる。

よって、タスクランナーを安全に使うためには env-cmd を用いるしか手段がない。