㊗️

DockerでNext.jsを扱った時に変更が反映されない。

に公開

起こったこと

Next.js、Rails、PostgreSQLをコンテナとしてdocker立ち上げた時にNext.js(フロントエンド側)の変更が反映されない。
ローカルのpage.tsxは更新済みだが、ブラウザに反映されない
多分コンテナ内のファイルが古いまま

開発環境

Macbook air m1
Next.js15系(webpack)
Rails7系
postgreSQL15

行ったこと

まずCursorのchatで原因を深掘り、「Next.js docker 反映されない」で調べました。
その上で原因ぽいのを洗い出しました。

ローカルの変更がコンテナ内のファイルと一致しているか?

まずローカルの変更がコンテナ内のファイルに反映されているか調べるために

# ローカルのファイルを確認
cat frontend/src/app/page.tsx | head -30

# コンテナ内のファイルを確認
docker compose exec frontend cat /app/src/app/page.tsx | head -30

を行い一致しているか確認しました。
結果としては一致しておらず変更が反映されてなかったです。
ここが違う場合は、ボリュームマウントの問題なので、cursorが提案してくれた
・ボリュームマウントの設定を変更
docker-compose.ymlで:delegatedオプションを追加
を行いました。

 frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    volumes:
      - ./frontend:/app:delegated #:delegatedを追加
      - /app/node_modules
      - /app/.next
    environment:
      - WATCHPACK_POLLING=true
      - CHOKIDAR_USEPOLLING=true

するとしっかりコンテナ内のファイルにもすぐ反映されるようになりました!

delegatedとは?

:delegatedオプションとは
Dockerのボリュームマウントで、Macのファイルシステム(macOS)向けの最適化オプションです。
なぜ必要だったか
問題の原因
MacのDocker Desktopは、ホスト(Mac)とコンテナ間でファイルを同期する際、デフォルトでは即座に同期しないことがあります。理由は以下の通りです。
macOSのファイルシステムの特性
macOSはファイル変更の通知を非同期で処理する
コンテナ側が変更を即座に検知できない場合がある
デフォルトのマウント動作
./frontend:/app だけだと、同期タイミングが不安定
ファイルを保存しても、コンテナ内に反映されるまで時間がかかる

:delegatedを追加すると:
・非同期書き込みの最適化
・macOS側の書き込みを優先
・コンテナ側への反映を効率的に処理
などがあります

ちなみにDockerのボリュームマウントには、Mac用に以下のオプションがあります:

:delegated(今回使用)

ホスト側の書き込みを優先
読み取りはコンテナ側が優先
開発環境に適している

:cached

読み取りをホスト側が優先
書き込みはコンテナ側が優先
読み取りが多い場合に有効

:consistent

完全に同期(最も遅い)
通常は不要

まとめ

・問題: MacのDocker Desktopでファイル同期が不安定
・原因: macOSのファイルシステムの非同期処理
・解決: :delegatedオプションでMac向けに最適化
・結果: ファイル変更が即座にコンテナ内に反映される
これで、ファイルを保存するたびにコンテナ内のファイルも更新され、Next.jsのホットリロードが正常に動作するようになりました!

Discussion