テックブログ執筆期間が近づいてくると毎回docker関係で頭を悩ませている男です。
はじまり
ある日、ローカルでフロントを開いたら画面が真っ白のまま動かず、描画されるのに5分以上かかっていることが分かりました。開発中にこれを何度も繰り返すのはあまりにも厳しいので原因を探すことにしました。
Viteの設定をいじっても焼け石にお水
最初は Vite を疑いました。optimizeDeps を設定したり、server.warmup を追加したり。
確かに数十秒は早くなったような…?でも結局トータルでは数分変わるのは変わらず。
そもそも docker compose logs を見ると Vite 自体は ready in 2.6s とすぐに立ち上がっています。サーバーは2秒、ブラウザでの表示までは5分~。完全に別の場所がボトルネックになっています。
試しに測ってみる
何が遅いのか、ファイルアクセス時間を素朴に計測してみることにしました。
docker exec frontend bash -c 'time find /usr/src/src -name "*.tsx" | wc -l'
# 79
# real 0m24.538s79ファイル数えるのに25秒。
おい待てい、find で25秒というのはとんでもなく遅いのでは….。比較のために node_modules(こちらは
Docker volume)を同じように測ると:
# 474 ディレクトリ
# real 0m0.119sほぼ一瞬。
同じコンテナの中なのに、windows側のファイルを覗きに行くと200倍くらい遅い。viteではなくI/O自体が異常に遅かったのです。
原因:ファイルシステム間の翻訳コスト
Docker Desktop on Windows は内部で WSL2 上に Linux VM を立てて、その中で Docker
を動かしています。コンテナ(Linux ext4)から
Windows(NTFS)のファイルにアクセスするには、毎回ファイルシステム間の変換が走ります。
1ファイルあたりは小さいオーバーヘッドでも、Vite は初回アクセスで src/
配下を全部舐めるので、積もり積もって5分~。
Vite の設定問題ではなく、もう一段下のレイヤーで起きていた現象でした。

じゃあどうするか
選択肢はいくつかありました。
- フロントだけ Docker から外して npm run dev — 一番速い。ただ「Docker前提で動く構成を維持したい」というチームの方針があったので保留
- Docker Desktop の Synchronized file shares —バインドマウントの代わりに高速な同期エンジンを使う機能。ただし Pro プラン以上が必要
- プロジェクトを WSL2 のファイルシステムに置く — Docker Desktop の中身が WSL2なので、ソースも同じ WSL2 側に置けばLinux 同士のアクセスになり、変換コストが消える
3番目を採用しました。Dockerは使い続けられるし、追加コストの発生もありません。
やったこと
ざっくり言えば、プロジェクトを C:\Users\... から WSL2 内の /root/work/... に引っ越しただけです。
引っ越しに伴って SSH 鍵や .env、SSL 証明書など gitignore 系のファイルをコピーし、/.docker/config.json の credsStoreを無効化、docker-compose.yml の secrets 参照先を調整、といった細かい修正が必要でした。
結果
docker exec frontend bash -c 'time find /usr/src/src -name "*.tsx" | wc -l'
# 79
# real 0m0.102s25秒 → 0.1秒
ブラウザでの初回表示も数秒以内に直りました。
おわりに
今回ようやく腰を上げて解決に向かいましたが、結果として開発時の体感が大きく変わりました。
WSL2 移行は一見手間に見えますが、やってしまえば普段通り Docker で開発できる状態に戻ります。ローカルが軽くなるだけで気分が違うので、同じ悩みを抱えながら放置している方には試してみる価値があると思います。