Docker + React 環境で node_modules が作れなかった話と学び

私は最近、React + Docker 環境でフロント学習を進めています。
その中で、Dockerコンテナ内で node_modules が作成されず npm install が不安定になるという問題に直面しました。今回は、その問題の原因と対策、学びを整理して共有します。
目次
1. 最初の問題
初回の Docker 環境構築で気づいたのは次の点です。
・コンテナ内に node_modules が存在しない
・package-lock.json が .package-lock.json というファイル名になっていた
その結果、npm install を実行しても依存関係が正しく反映されず、Reactコンテナが起動できない状況でした。
学習用の小さなプロジェクトでも、node_modulesがないと開発が全く進まないので、ここで立ち止まることに。
2. 原因の調査
調べてみると、主な原因は Docker とホスト側のファイル管理の差にありました。
2-1. 匿名ボリュームの設定
Dockerでは /app/node_modules のようなディレクトリを匿名ボリューム化していないと、ホスト側の空の node_modules に上書きされてしまいます。
つまり、コンテナ内で依存をインストールしても、ホスト側で node_modules が存在しない場合、インストール済みのものが消されてしまうのです。
この匿名ボリュームの設定をしていなかったことが、node_modulesが作れなかった最大の原因でした。
2-2. ホスト側での依存関係生成
さらに重要だったのが、ホスト側で npm install を実行して package-lock.json を生成し、それをコンテナに渡すというステップです。
・ホスト側で node_modules と lockfile を作る
・その lockfile を Docker に渡すことで、コンテナ内でも再現性のある依存関係が作成される
この手順を踏まないと、コンテナ起動時に npm install が正しく機能せず、node_modules が生成されないままになります。
3. Docker 内での確認方法
開発中にコンテナが起動しない場合でも、docker-compose run –rm frontend bash を使うと、コンテナにログインしてファイルツリーや設定を確認できます。
これにより、node_modules が本当に存在しているか、lockfile が正しくマウントされているかなどを確認でき、原因特定がかなりスムーズになりました。
4. Node バージョンの整合
ホスト側と Docker の Node バージョンの違いも問題を複雑にしました。
私の環境では:
・Docker 側:Node 20 系(v20.19.4)
・ホスト側:Node 22 系
という差があり、npm install に影響していました。
学習や小規模プロジェクトでは、Voltaなどでプロジェクト単位の Node バージョンを固定して Docker と合わせると依存関係の再現性が向上します。
私の場合は volta pin node@20.19.4 で揃えました。
5. 対策のまとめ
今回の学びを整理すると、Docker + React 環境で node_modules が作れない場合のベストプラクティスは以下です。
1.匿名ボリューム化
・/app/node_modules を匿名ボリューム化して、ホスト側に存在しなくてもコンテナ内の node_modules が消されないようにする
2.ホスト側で npm install + package-lock.json の生成
・ホスト側で依存をインストールして lockfile を作り、それをコンテナに渡す
・これでコンテナ内でも正しく node_modules が再現される
3.Node バージョンの統一
・Docker とホスト側で Node バージョンを合わせる
・Volta のようなツールを用いてプロジェクト単位で固定するのがおすすめ
6. 振り返り
今回の試行錯誤を通して、Docker でのフロント開発における依存関係管理の重要性を強く実感しました。
・匿名ボリュームの有無で node_modules が消える
・ホスト側で lockfile を生成してコンテナに渡す
・Node バージョンを揃える
この3つを押さえておくと、学習用でもスムーズに環境構築が可能になります。
また、コンテナが起動しないときでもログインして確認できる docker-compose run –rm frontend bash の活用も、大きな助けになりました。
こうした小さなトラブルシュートの積み重ねが、Docker + React の理解を深める近道だと感じます。
今回の体験は学習用の小さなプロジェクトでしたが、環境構築の再現性や依存関係管理の重要性を身をもって学べる内容でした。
今後もこの知見を活かして、より安定した Docker 環境でのフロント開発に挑戦していきたいと思います。