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_ENV が production のままだと、npmはdevDependenciesを省略する動きになります。
症状: --save-devが成功したのにパッケージが使えない
典型的な症状は次です。
npm install --save-dev <package>がエラーなしで終わるpackage.jsonにはdevDependenciesが追加されている- しかし
node_modules/.bin/<command>が存在しない npm run devやnpm 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はまた省略されます。
先に見る順番は次です。
$env:NODE_ENVを確認する- User/Machineスコープの
NODE_ENVを確認する npm install --include=devで復旧するnode_modules/.binに対象コマンドがあるか確認するnpm run devやnpm 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 install と next 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.jsonのdevscriptで開発モードを明示しているかnpm run devとnpm run buildの失敗が同じ環境変数から来ていないか
まとめ
npm install --save-dev が成功したのにdevDependenciesが入らない時は、パッケージやnpmキャッシュより先に NODE_ENV=production を疑います。
NODE_ENV は子プロセスへ継承されます。意図せずproductionになっていると、npmがdevDependenciesを省略し、開発ツールが存在しない状態になります。
復旧は、環境変数を確認し、npm install --include=dev でdevDependenciesを明示的に入れ直すことです。原因の層を間違えなければ、不要な削除や再インストールを避けられます。