.next/キャッシュは引越しを知らなかった
Claude の設定ファイルを一元管理する仕組みを作った
今日は機能追加ではなく、開発環境の土台を整える作業をした。
複数のアプリケーションプロジェクトで Claude Code の設定ファイルを使い回したい、という課題があった。サブエージェントの定義・開発ルール・スキル——これらは今まで各プロジェクトの中に個別にコピーして置いていた。同じファイルをプロジェクトごとに持つのは管理が煩雑になる。そこで dev という親リポジトリを新設して、.claude/agents・.claude/rules・.claude/skills・docs/01_開発標準 の実体をそこに集約した。
各プロジェクトからは symlink(シンボリックリンク — 別の場所にあるファイルへのショートカット)で参照する形にした。技術ブログプラットフォーム code-notes が、その最初の移行先になった。
マウント設計は「dev 全体」ではなく「4本を個別に」
devcontainer(Docker コンテナとして定義した開発環境)を使っているため、ホストのフォルダをコンテナ内に見せる設定——ボリュームマウント——も合わせて変更が必要だった。
最初に思いついたのは「dev リポジトリ全体をマウントすれば一発解決では」というアイデアだ。しかしそれをやると、code-notes のコンテナから hp-sy(将来追加予定の別アプリ)のファイルが丸ごと見えてしまう。アプリ同士がお互いのファイルを読み書きできる状態は作りたくなかったので、このアイデアは棄却した。
代わりに採用したのが、共有パスを4本だけ個別にマウントする方式だ。
変更前の docker-compose.yml はこうだった。
volumes:
- ..:/workspaces/dev:cached
変更後はこう変えた。
volumes:
- ..:/workspaces/dev/code-notes:cached
- ../../.claude/agents:/workspaces/dev/.claude/agents:cached
- ../../.claude/rules:/workspaces/dev/.claude/rules:cached
- ../../.claude/skills:/workspaces/dev/.claude/skills:cached
- ../../docs/01_開発標準:/workspaces/dev/docs/01_開発標準:cached
1行目で code-notes 本体のマウント先を変更し、残り4行で共有したい設定ファイルを個別にマウントしている。これで code-notes コンテナ内からは code-notes と共有設定だけが見え、他のアプリのファイルには触れられなくなった。
もう一つ意識したのが、.claude ディレクトリ全体ではなく agents・rules・skills の3サブディレクトリを個別に指定した点だ。将来 dev/.claude/ 直下に新しいファイルが追加されたとき、意図せず全プロジェクトへ共有されてしまうのを防ぐための先手になる。
合わせて devcontainer.json の workspaceFolder(VS Code が開くフォルダのパス設定)を /workspaces/dev から /workspaces/dev/code-notes に変更し、.claude/settings.json の PostToolUse Hook(ツール実行後に自動で走る処理)のパスも同様に修正した。
踏んだ地雷:Turbopack が FATAL エラーを大量出力
コンテナを再ビルドして next dev を起動すると、次のような FATAL エラーが大量に出た。
FATAL[...] next_dev_server::project message="Next.js package not found at path '/workspaces/dev/node_modules/next/package.json'"
FATAL[...] next_dev_server::project message="Next.js package not found at path '/workspaces/dev/node_modules/next/package.json'"
workspaceFolder を変えたのだから、パスが変わるのは当然だ。問題は、古いパス /workspaces/dev/ がどこかに残っていること。調べてみると、.next/required-server-files.json の中に "distDir": "/workspaces/dev/.next" という古いパスが入っていた。
.next/ は Turbopack(Next.js の高速ビルドエンジン)がビルド成果物やキャッシュを置くフォルダだ。そのキャッシュに、旧パスが絶対パスとして焼き込まれていた。コンテナ内のパスが変わっても .next/ は黙って古いパスを返し続けていた——キャッシュは引越しを知らなかった、というわけだ。
対処はシンプルで、rm -rf .next/ でキャッシュを丸ごと消すだけ。クリア後は FATAL エラーが消えて、アプリが正常に起動した。
動作確認
移行後に3点確認した。
まず ls /workspaces/dev/ の出力が code-notes と docs だけになっていること。hp-sy/ が見えないことで、アプリ間の遮断が機能していると確認できた。
次に Claude Code 起動時、サブエージェント定義・ルール・スキルがシステムプロンプトに読み込まれていること。symlink 経由でのファイルロードも問題なく動いていた。
最後にテストを一括実行した。E2E が12件合格(既存の fixme は12件)、UT が430件合格。移行作業でテストが壊れていないことを確認できた。
今日の学び
- マウント範囲設計は共有と遮断の設計そのもの。 dev 全体をマウントするのではなく4本のパスを個別にマウントすることで、必要なものだけを共有しつつアプリ間を遮断できた
- サブディレクトリ単位でマウントして、意図しない共有を防ぐ。
.claudeディレクトリ全体ではなくagents・rules・skillsを個別に指定することで、将来ファイルが増えたときの「意図せぬ全共有」を先に塞げる - workspaceFolder を変えたら .next/ キャッシュを消す。 Turbopack のキャッシュは旧パスを絶対参照で持っているため、移行後は
rm -rf .next/が必要だった
本記事は Sonnet 4.6(claude-sonnet-4-6)が生成しました。