1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js 16 (Turbopack) はフォルダリネームに弱い? 高速リロードループの正体を調べた

1
Posted at

Next.js 16 (Turbopack) はフォルダリネームに弱い? 高速リロードループの正体を調べた

TL;DR

  • プロジェクトのフォルダ名を変更したら npm run devAn unexpected Turbopack error occurred. で落ちるようになった
  • 原因は .next 配下に残っていたTurbopackの永続キャッシュが、リネーム前の絶対パスを参照していたこと
  • .nextnode_modules/.cache を削除したら解消した
  • Next.js/Turbopackプロジェクトをリネーム・移動するときは、再起動前に .next を消すのがお作法として安全

発生した症状

ローカルで作業していたNext.jsプロジェクトのフォルダ名を変更したところ、次回の npm run dev 起動時にこんなエラーが出るようになりました。

An unexpected Turbopack error occurred. A panic log has been written to

さらに実際にブラウザで開いてみると、エラー画面が固定表示されるのではなく、ページが高速でリロードを繰り返すループのような見た目になっていました。単発のクラッシュではなく、何かが繰り返し発生している様子です。

調査

まず、フォルダリネームで壊れそうな箇所として .next ディレクトリを疑いました。Next.js 16はデフォルトでTurbopackを使っており、devサーバーの起動を高速化するために .next/turbopack.next/dev/cache/turbopack にファイルシステムキャッシュ(File System Caching、Next.js 16.1+で安定版・デフォルト有効)を持っています。

このキャッシュの中身を覗くと、リネーム前のフォルダ名を含む絶対パス(例: /Users/xxx/旧フォルダ名/src/...)を参照する情報が残っていました。

原因

Turbopackのファイルシステムキャッシュは、モジュールを絶対パスをキーにしてディスク上に保存します。フォルダ名を変更すると、プロジェクト内の全ソースファイルの絶対パスが一斉に変わりますが、.next の中の古いキャッシュはリネーム前のパスを指したままになります。

次回起動時、Turbopackは「キャッシュ上のパス」と「実際のファイルシステム上のパス」を照合しようとしますが、両者が一致しません。この不整合を検出したとき、Turbopack(Rustで実装されたコアエンジン)はそれを回復可能なキャッシュミスとして扱いきれず、panic!(Rustの回復不能なアサーション違反)を起こしてプロセスごと落ちる——これが「パニックログが書き出される」という挙動の正体でした。

なぜ「高速リロードのループ」に見えたのか

これは単発のクラッシュでは終わりませんでした。理由はNext.jsのHMR(Hot Module Replacement)クライアントの仕組みにあります。

  1. ブラウザとdevサーバーはHMR用のWebSocketで繋がっており、Fast Refreshは「接続が切れたら安全のためフルリロードする」という設計になっている
  2. Turbopackが壊れたキャッシュを読もうとしてパニック → プロセス(またはワーカー)が落ちる → WebSocket接続が切断される
  3. クライアント側がこれを検知して自動的にページをフルリロードする
  4. リロードで再びdevサーバーにリクエストが飛び、Turbopackはまた同じ壊れたキャッシュエントリに当たって再パニック
  5. 3〜4が繰り返される

つまり、「パニック→切断→自動リロード→同じ壊れたキャッシュに再度到達→再パニック」というループが、壊れたキャッシュを取り除くまで自動的に続いていた、というのが見た目の正体でした。

解決方法

.next ディレクトリ(Turbopackの永続キャッシュ本体)と node_modules/.cache を削除し、devサーバーを再起動しました。

rm -rf .next node_modules/.cache
npm run dev

これにより、旧パスを参照していたキャッシュエントリが一掃されます。次の起動時、Turbopackはキャッシュなしの状態から、新しい絶対パスだけを前提にモジュールグラフをゼロから構築するため、パスの不整合が起きずパニックも再発しませんでした。

キャッシュを消すデメリットは?

キャッシュ削除で失うのは基本的に速度だけです。

  • 次回の npm run dev は増分コンパイル結果が無いため、コールドスタート相当の待ち時間になる
  • npm run build も同様にフルビルドになり、プロジェクト規模次第で数十秒〜数分伸びる

一方で、コードの正しさや出力内容には影響しません。キャッシュは「同じ入力から同じ出力を再計算せず使い回す」ための最適化に過ぎず、消しても次回のビルドで同じ成果物が再生成されます。node_modules 本体(依存パッケージ)は無傷なので npm install のやり直しも不要でした。

これはTurbopack特有の問題か

原因である「絶対パスをキーにしたキャッシュが、パスの変化で陳腐化する」こと自体は、webpackなど他のビルドツールの永続キャッシュにも共通し得る一般的な問題です。webpackも cache: { type: 'filesystem' } でディスクキャッシュを持ち、そこにも絶対パス由来の情報が含まれます。

ただし、症状として現れた**「パニックしてプロセスごとクラッシュする」**という部分は、Turbopack特有の挙動だと考えられます。webpackは長年運用されてきた実装で、パスやハッシュの不一致を検出しても、静かにキャッシュミス扱いにして再ビルドするだけで済むことがほとんどです。対してTurbopackのファイルシステムキャッシュは、Next.js 16.1で安定版になったばかりの比較的新しい機能で、こうしたファイルシステムの変化(パスの移動・リネーム)に対する耐性は、webpackほど枯れていない可能性があります(※ここは筆者の推測であり、Vercelの公式見解ではありません)。

まとめ

  • Next.js/Turbopackプロジェクトのフォルダをリネーム・移動したら、再起動前に必ず .next を削除する
  • 「高速リロードが延々と続く」ような不可解な挙動を見たら、まず .next 配下のキャッシュ破損を疑うとよい
  • キャッシュ削除は「次回だけ少し遅くなる」以外のデメリットがなく、安全に試せる対処法
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?