next devだけCSSが壊れる原因はNODE_ENV=productionだった
Next.jsで next build は成功するのに、next dev だけCSSで落ちることがあります。
このとき globals.css の構文、PostCSS、Turbopack、webpack設定を疑いたくなりますが、原因がCSSではない場合があります。今回の原因は、親プロセスから継承された NODE_ENV=production でした。
起きた症状
ローカル開発で起きた症状は次の通りです。
npm run buildは成功するnpm run devだけ失敗するglobals.cssの普通のCSSでModule parse failed: Unexpected tokenが出る- エラー位置は
*,のような正常なCSSセレクタ付近に見える
代表的には、次のような見え方になります。
Module parse failed: Unexpected token (2:0)
このエラーだけを見ると、CSSローダーやPostCSS設定が壊れているように見えます。しかし、next build が通っているなら「CSSの構文そのものが間違っている」と決め打ちしない方が安全です。
最初に疑ったもの
まず疑う候補は自然にいくつかあります。
globals.cssの構文ミスpostcss.config.jsの不足や形式ミス- Tailwind CSSやCSS Modulesの設定
- Next.jsのwebpack/Turbopack切り替え
- キャッシュや
.next/の破損
これらは調べる価値があります。ただし、今回のように next build は通るのに next dev だけ落ちる場合は、設定ファイルより先に環境変数を確認した方が早いことがあります。
本当の原因はNODE_ENV=productionだった
原因は、シェルまたはユーザー環境に NODE_ENV=production が残っていたことでした。
next dev は開発サーバーを起動するコマンドですが、子プロセスは親プロセスの環境変数を継承します。そのため、呼び出し側の環境に NODE_ENV=production が入っていると、開発用コマンドのつもりでもproduction向けの挙動が混ざります。
この状態では、CSS処理の初期化や依存関係の扱いが期待とずれて、結果として「正常なCSSがJavaScriptとしてパースされている」ようなエラーに見えることがあります。
Next.js公式ドキュメントも、NODE_ENV はReactエコシステムで特別扱いされる値であり、想定外の値や混ざった設定は確認対象だと説明しています。
参考: Next.js: Non-Standard NODE_ENV
npm installにも影響する
NODE_ENV=production の影響は next dev だけではありません。
npmの公式ドキュメントでは、NODE_ENV が production の場合、omit の既定値に dev が入ると説明されています。つまり、ローカルで普通に npm install したつもりでも、devDependenciesが物理的に node_modules に入らないことがあります。
参考: npm-install: omit / include
この状態になると、次のような二次障害が起きます。
cross-envが見つからない- TypeScriptやESLintなどの開発用パッケージが見つからない
npm install --save-dev <package>したはずなのに実行時に解決できない- ビルドや開発サーバーの失敗原因が依存関係ミスに見える
CSSエラーとdevDependencies欠落が同時期に出ているなら、かなり強く NODE_ENV 汚染を疑ってよいです。
PowerShellで確認する
WindowsのPowerShellでは、まず現在のセッション値を確認します。
$env:NODE_ENV
何も表示されなければ、現在のPowerShellセッションには直接設定されていません。
次に、ユーザー環境変数とマシン環境変数を確認します。
[Environment]::GetEnvironmentVariable("NODE_ENV", "User")
[Environment]::GetEnvironmentVariable("NODE_ENV", "Machine")
ここで production が出る場合、ターミナルを開き直しても子プロセスに継承される可能性があります。
一時的に確認するだけなら、次のように開発モードを明示して実行します。
$env:NODE_ENV = "development"
npm run dev
ただし、この方法はそのPowerShellセッションにだけ効きます。再発防止には、スクリプト側で明示する方が安定します。
package.jsonで直す
ローカル環境に依存させないために、package.json のスクリプトで NODE_ENV を明示します。
Windows、macOS、Linuxで同じ書き方にしたい場合は cross-env を使います。cross-env は、OSごとの環境変数指定の差を吸収するためのパッケージです。
参考: cross-env README
例:
{
"scripts": {
"dev": "cross-env NODE_ENV=development next dev",
"build": "cross-env NODE_ENV=production next build",
"start": "cross-env NODE_ENV=production next start"
}
}
devDependenciesが抜けている可能性がある場合は、明示的にdevDependenciesも入れ直します。
npm install --include=dev
cross-env 自体が入っていない場合は、先にdevDependencies込みでインストールしてください。
npm install --include=dev
npm install --save-dev cross-env
CSSやPostCSSを見る前に切り分ける
同じ Module parse failed でも、原因は複数あります。次の順番で切り分けると、遠回りを減らせます。
1. buildとdevの差を見る
npm run build
npm run dev
build だけ通るなら、CSSファイルの構文ミスよりも「開発サーバー固有の状態」を疑います。
2. NODE_ENVを見る
$env:NODE_ENV
[Environment]::GetEnvironmentVariable("NODE_ENV", "User")
[Environment]::GetEnvironmentVariable("NODE_ENV", "Machine")
どこかで production が出たら、まずそこを潰します。
3. 依存関係が入っているか見る
npm ls cross-env
npm ls typescript
devDependenciesが入っていないなら、npm install --include=dev で入れ直します。
4. それでも残るならCSS設定を見る
ここまで確認しても直らない場合に、PostCSS、Tailwind CSS、Next.js設定、.next/ キャッシュを見ます。
この順番にすると、「CSSエラーに見える環境変数の問題」を設定変更で無理に直そうとする事故を避けられます。
なぜこの問題は見つけにくいのか
この問題が厄介なのは、エラーメッセージに NODE_ENV=production が出ないことです。
画面上はCSS parse errorに見えます。npm側でも、devDependenciesが入らない理由が毎回大きく警告されるわけではありません。結果として、次のような誤診が起きやすくなります。
- Turbopackの問題だと思い込む
postcss.config.jsを何度も書き換えるglobals.cssの書き方を疑う.next/を消して直ったかどうかだけを見る- パッケージのインストール失敗を別問題として扱う
しかし、親環境の NODE_ENV がproductionなら、これらは同じ根から出た症状かもしれません。
再発防止のチェックリスト
devスクリプトではNODE_ENV=developmentを明示するbuild/startではNODE_ENV=productionを明示する- Windowsでは
User/Machinescope の環境変数も確認する npm installでdevDependenciesが怪しいときは--include=devを使う- CSS parse errorでも、
next buildが通るなら環境変数を先に見る
まとめ
next dev だけCSSで落ちると、CSSやPostCSSを直したくなります。
ただ、next build が通るなら、ファイル内容そのものではなく、開発サーバーの実行環境が壊れている可能性があります。特に NODE_ENV=production が親プロセスから継承されていると、next dev や npm install の挙動が静かに変わります。
まずは次の3つを確認してください。
$env:NODE_ENV
[Environment]::GetEnvironmentVariable("NODE_ENV", "User")
[Environment]::GetEnvironmentVariable("NODE_ENV", "Machine")
ここで production が出るなら、CSSを直す前に環境変数を直す方が先です。