← ./articles-ja

npm installでdevDependenciesが入らない時はNODE_ENV=productionを疑う

npm install --save-dev は成功したように見えるのに、入れたはずのパッケージが node_modules にありません。

たとえば次のような状況です。

npm install --save-dev cross-env
npm run dev

その後、スクリプトで次のように落ちます。

'cross-env' is not recognized as an internal or external command

この時、package名やnpmのキャッシュを疑う前に、NODE_ENV=production が混ざっていないか確認してください。NODE_ENVproduction のままだと、npmはdevDependenciesを省略する動きになります。

症状: --save-devが成功したのにパッケージが使えない

典型的な症状は次です。

  • npm install --save-dev <package> がエラーなしで終わる
  • package.json にはdevDependenciesが追加されている
  • しかし node_modules/.bin/<command> が存在しない
  • npm run devnpm run build でコマンドが見つからない
  • 別のターミナルや別PCでは同じ手順が通る

この状態では、インストール対象のパッケージが悪いとは限りません。npmがdevDependenciesをインストール対象から外している可能性があります。

原因: NODE_ENV=productionがnpm installに継承されている

Node.js系のツールでは、NODE_ENV が実行モードの判定に使われます。

NODE_ENV=production がセッション環境に残っていると、npm installもその値を継承します。その結果、devDependenciesが省略されます。

重要なのは、ユーザーが明示的に --production を付けていなくても起きることです。

NODE_ENV=production
  -> npm install
  -> devDependencies omitted

CI、前回のシェル設定、AIコーディングツールの実行環境、IDE内ターミナルなどが環境変数を残していると、意図せずこの状態になります。

まずNODE_ENVを確認する

PowerShellでは次を実行します。

$env:NODE_ENV

production と表示されたら、そのセッションの子プロセスはproduction扱いになります。

ユーザー環境変数やマシン環境変数に入っているかも確認します。

[Environment]::GetEnvironmentVariable("NODE_ENV", "User")
[Environment]::GetEnvironmentVariable("NODE_ENV", "Machine")

どちらかに production が入っている場合、ターミナルを開き直しても再発します。プロジェクト単位でproductionにしたいだけなら、グローバルな環境変数として固定しないほうが安全です。

BashやGit Bashでは次です。

echo "$NODE_ENV"

復旧: --include=devでdevDependenciesを明示的に入れる

すでに NODE_ENV=production が疑わしい場合は、devDependenciesを明示して入れ直します。

npm install --include=dev

特定のdevDependencyを追加したい場合も、環境をdevelopmentにしてから実行します。

$env:NODE_ENV = "development"
npm install --save-dev cross-env

一時的にそのコマンドだけ環境を固定したい場合は、cross-env を使える状態なら次のようにできます。

npx cross-env NODE_ENV=development npm install --include=dev

ただし、cross-env 自体がまだ入っていない環境では使えません。その場合はPowerShellやシェルの環境変数を先に直します。

package.jsonのscriptsで開発モードを固定する

開発サーバーは、セッションの NODE_ENV に依存させないほうが安全です。

{
  "scripts": {
    "dev": "cross-env NODE_ENV=development next dev",
    "build": "next build"
  }
}

これで、親プロセスの環境が汚れていても npm run dev はdevelopmentとして起動します。

build はNext.jsや多くのツールが自分でproduction相当の処理を行うため、無理に NODE_ENV=production を書かなくてもよい場面があります。必要ならプロジェクトの方針に合わせて明示します。

npmキャッシュ削除から始めない

この症状で、いきなり次のような操作から始めるのはおすすめしません。

npm cache clean --force
Remove-Item -Recurse node_modules
Remove-Item package-lock.json

原因が NODE_ENV=production なら、これらを実行しても同じ環境で再インストールする限りdevDependenciesはまた省略されます。

先に見る順番は次です。

  1. $env:NODE_ENV を確認する
  2. User/Machineスコープの NODE_ENV を確認する
  3. npm install --include=dev で復旧する
  4. node_modules/.bin に対象コマンドがあるか確認する
  5. npm run devnpm run build を再実行する

削除や再インストールは、環境変数を確認した後で十分です。

next devのCSSエラーと同じ根になることがある

NODE_ENV=production 汚染は、npm installだけでなく開発サーバーにも影響します。

たとえばNext.jsでは、next build は通るのに next dev だけCSS parse errorになることがあります。これはCSS自体ではなく、開発サーバーがproduction扱いで起動していることが原因になる場合があります。

この場合、症状は別でも根は同じです。

NODE_ENV=production
  -> npm install skips devDependencies
  -> next dev starts with wrong assumptions

npm installnext dev の両方が変な壊れ方をしているなら、環境変数を最初に見ます。

関連: next devだけCSSが壊れる原因はNODE_ENV=productionだった

OneDrive配下で node_modules そのものが壊れる・置き換わる場合は原因が別です。その場合は OneDrive上のNode.js開発はnode_modulesをjunctionで外へ逃がす を確認してください。

確認チェックリスト

次を順番に確認します。

  • $env:NODE_ENV または echo "$NODE_ENV"production になっていないか
  • User/Machineスコープに NODE_ENV=production が固定されていないか
  • npm install --include=dev を実行したか
  • node_modules/.bin/<command> が存在するか
  • package.jsondev scriptで開発モードを明示しているか
  • npm run devnpm run build の失敗が同じ環境変数から来ていないか

まとめ

npm install --save-dev が成功したのにdevDependenciesが入らない時は、パッケージやnpmキャッシュより先に NODE_ENV=production を疑います。

NODE_ENV は子プロセスへ継承されます。意図せずproductionになっていると、npmがdevDependenciesを省略し、開発ツールが存在しない状態になります。

復旧は、環境変数を確認し、npm install --include=dev でdevDependenciesを明示的に入れ直すことです。原因の層を間違えなければ、不要な削除や再インストールを避けられます。