第12章:ソース共有(bind mount)とnode_modules問題👟🧨
この章、ComposeでNode/TSを開発するときに一番ハマりがちな「node_modulesどうするの?」を、詰まらない型に固定します💪✨
(やることはシンプル:ソースだけ共有/依存はコンテナ側に置く)
1) この章でできるようになること🎯✨
- 保存したら即反映!の開発体験(bind mount)を作れる📝⚡
node_modulesが原因の「動かない」「重い」「壊れる」を避けられる🧯- 依存関係の更新も、決まった手順で安全に回せる🔁✅
2) まずはイメージ:何を共有して、何を共有しない?🧠🧩
- bind mount:ホストのフォルダをコンテナに“そのまま見せる”仕組み。保存が即反映されるので開発向き📌 (Docker Documentation)
- volume:Dockerが管理する保存領域。DBデータや
node_modulesみたいな「大量&OS依存」なものに向いてる📦 (Docker Documentation)
ここで大事なのが👇
✅ 共有していい:src/、package.json、tsconfig.json、設定ファイル
❌ 共有しないほうがいい:node_modules/(特にWindows環境だと地雷率UP💣)
3) node_modules問題 “あるある”3連発😇💥
あるある①:コンテナでnpm run devしたら「モジュールが見つからない」😵
原因:.:/appみたいにプロジェクト全体をbind mountすると、イメージ内で作った/app/node_modulesがマウントに隠れて見えなくなるやつです🙈
あるある②:ホスト側にnode_modulesが生えてPCが重くなる🪨
原因:コンテナのnpm installが、bind mount経由でホスト側に書き込むパターン(ファイル数が多すぎて地獄😇)
あるある③:ネイティブ依存(例:bcrypt等)がOS違いで壊れる🧨
原因:Windowsで入れたnode_modulesをLinuxコンテナで使おうとして、バイナリが合わずに爆発💥
→ 依存はコンテナ側(Linux側)で入れるのが安定です👍
4) 結論:黄金パターン🏆「ソースはbind mount、node_modulesはvolume」
やることはこれだけ👇✨
.:/appでソース共有📝/app/node_modulesだけはnamed volumeにして隔離🧊
これで「即反映」と「依存の安定」を両立できます🔥
5) 実装:compose.yamlに追記しよう🛠️🐳
例:サービス名を
api、作業ディレクトリを/appとします(構成は適宜読み替えOK🙆♂️)
services:
api:
build:
context: .
dockerfile: Dockerfile
working_dir: /app
volumes:
- .:/app
- api_node_modules:/app/node_modules
command: npm run dev
environment:
# 監視が効かない/遅い時の保険(必要になったらON)
# CHOKIDAR_USEPOLLING: "true"
# CHOKIDAR_INTERVAL: "250"
NODE_ENV: development
volumes:
api_node_modules:
ポイントはここ👇👀
- .:/app(ソース共有)- api_node_modules:/app/node_modules(依存を隔離) この2つの“合わせ技”が最強です🏆
6) 依存を入れる:最初に1回だけnpm ci(推奨)📦⚡
named volumeは最初は空なので、最初に依存を入れます。
docker compose run --rm api npm ci
npm ciはロックファイル前提で再現性が高いので教材向き👍- その後は普通に起動👇
docker compose up
7) 依存を更新したときの“儀式”🔁✨(固定手順)
package.jsonやロックファイルを変更したら、これだけでOK👇
docker compose run --rm api npm ci
docker compose up
「依存が変わったらこの2行」って覚えると、事故りにくいです🧯✅
8) Windowsでハマりやすい“速度&監視”の話🪟🐢➡️🐇
bind mountは便利だけど、Windowsだと ファイルの置き場所で体感が激変します⚠️
- Linuxコンテナにbind mountするコードは、可能なら WSL2側のLinuxファイルシステムに置くと速い&変更検知もしやすいです🏎️💨 (Docker Documentation) (Docker DesktopのWSL2ベストプラクティスで明言されています📌)
もし「保存しても反映されない」「監視が不安定」なら、まずここを疑うのが近道です🔎✨ (Docker Documentation)
9) よくあるトラブルと直し方🧯🛠️
Q1. Cannot find module ... が出る😵
✅ まずこれ👇(だいたい“volumeが空”)
docker compose run --rm api npm ci
Q2. node_modulesがホスト側にできて困る😇
✅ compose.yamlで/app/node_modulesがvolumeになってるか確認👀
(- api_node_modules:/app/node_modules が必要)
Q3. ホットリロードが効かない/遅い🐢
✅ まず「コードの置き場所」を見直し(WSL2側が強い) (Docker Documentation)
✅ 次に保険として polling をON(上のCHOKIDAR_USEPOLLING)🔁
※ pollingは効くけどCPU増えがちなので、最後の手段でOK👌
10) AIに手伝わせるコツ🤖🧠(短くて効く指示)
「たたき台を出させて、人間がチェック」がおすすめです✅ 例(そのまま貼ってOK)👇
docker composeでNode(TypeScript)開発環境を作っています。
要件:
- ソースはbind mountで即反映
- node_modulesはコンテナ側に隔離(named volume)
- 依存更新は docker compose run --rm api npm ci で行いたい
compose.yamlの volumes 構成と、落とし穴チェックリストを提案して
11) ミニ演習🎒✨(理解が爆速になる)
演習A:わざと壊して直す💥➡️✅
api_node_modules:/app/node_modulesを一旦消す- 起動してエラーを見る
- もう一回戻して、
npm ciで復活させる
「何が原因で何が効くか」が一発で腹落ちします😋
演習B:依存を追加して儀式を回す➕🔁
- 何か1つ依存を追加(例:
zodなど) - ロックファイル更新
docker compose run --rm api npm ci→docker compose up
12) まとめ:この章の“合言葉”🧠✨
- **ソースは共有(bind mount)**📝
- **依存は隔離(volume)**📦
- **依存更新は
docker compose run --rm ... npm ci**🔁
この型にしておくと、次の「サービス間通信」「起動順」「マイグレーション自動化」もスムーズに進みますよ〜🚀🔥
必要なら、あなたの第11章のDockerfile/フォルダ構成(例:apps/apiみたいな形)に合わせて、この章のcompose.yamlを“実物ベース”に最適化した版も作れます🙆♂️✨