【初めに】
こんにちは。
@hayatohanaoka です。
休日に遊び感覚で React
を Docker
で動かせるようにしてみたところ、
ホットリロード周りでいくつか学びがあったので残します。
出来としては雑でお粗末なものかもしれないのですが、誰かの助けになれば幸いです。
【リポジトリ】
「とりあえず中身見せろや!!」
って人向けに、冒頭で置いておきます...
sample-react
【環境】
マシン
M3 Mac
コンテナマネージャ
Rancher Desktop
言語
typescript 5.6.2
ランタイム
node 23.7.0
ライブラリ
react 18.3.1
【ReactAppの作成】
公式Docs に従ってコマンド実行しただけです。
ここはそこまで大変でないのと、次のトピックが主題なので割愛。
【コンテナ化】
Dockerfile
を作成して、コンテナ化していきます。
Dockerfile
の解説を少し挟むと、コンテナの元になる image
の作成の際に必要となるファイルです。
ここに書いたステップを元に image
を作成し、保存します。
FROM node:23-alpine
WORKDIR /app
# 依存関係のインストール
COPY package*.json ./
RUN npm install
# ソースコードのコピー
COPY . .
# アプリケーションの起動
CMD ["npm", "run", "dev"]
ローカルで実行するために簡単に用意したため、
ビルドと実行のステぷを分けること(マルチステージビルド)はしていません。
やっていることは非常にシンプルなので、初心者でも理解しやすいです。
- 土台となるイメージを用意する(
node:23-alpine
) -
package.json
を元に、依存関係をインストールする - ソースコードを元に
npm run dev
でアプリケーションを起動する
こちらについても、特筆すべき点はありません。
【ホットリロードの有効化】
今回の記事の主題です。
編集が必要になったのは以下のファイルです。
- docker-compose.yaml
- vite.config.ts
上から順に解説します。
docker-compose.yaml
複数のコンテナをどのように立ち上げるか設定できるファイル。
-
image
の作成の際にどのDockerfileやファイルを参照するか - どのポートを繋ぎ合わせるのか
- 環境変数には何を使用するか
等が設定できます。
services:
react:
build:
context: ../../
dockerfile: environments/local/Dockerfile
ports:
- 3000:5173 # host_port:container_port
volumes: # ホストのディレクトリをマウントして、コンテナ内のディレクトリに反映
- ../../src:/app/src
environment:
# ホットリロードのために必要なオプション値
- CHOKIDAR_USEPOLLING=true
- WATCHPACK_POLLING=true
ここでは以下の工夫が必要でした。
- ポートフォワード
-
localhost:3000
でリクエストしたかったので、ports
で指定
-
- ボリュームマウント
- ここがないと、ローカルの変更がコンテ内部に反映されません
- 環境変数の設定
- ここがないと、ソースコードの変更が検知されません
-
vite.config.ts
で設定することも可能- ローカルで
npm run dev
を行う際に不要な設定のため、こちらで設定した
- ローカルで
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
// サーバがリッスンするホストとポートを設定
server: {
host: true,
port: 5173,
},
})
こちらでは以下の設定を行なっています。
- viteが立ち上げるサーバーと通信可能なホストとポートを設定する
-
host
-
0.0.0.0
またはtrue
を設定すると、全ホストを許可 - コンテナ内部の
localhost
と、 ホストマシンのlocalhost
が別のものなので、
繋ぎ合わせるために必要
-
-
port
- 今回は
5173
を許可
- 今回は
-
図にするとこんな感じだと思います。
【実行】
いよいよ実行です...!!
以下のコマンドを実行します。
$ cd environments/local
$ docker compose up --build
Compose can now delegate builds to bake for better performance.
To do so, set COMPOSE_BAKE=true.
[+] Building 2.4s (11/11) FINISHED docker:rancher-desktop
=> [react internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 250B 0.0s
=> [react internal] load metadata for docker.io/library/node:23-alpine 1.4s
=> [react internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [react 1/5] FROM docker.io/library/node:23-alpine@sha256:a34e14ef1df25b58258956049ab5a71ea7f0d498e41d0b514f4b8de09af09456 0.0s
=> [react internal] load build context 0.2s
=> => transferring context: 453.30kB 0.2s
=> CACHED [react 2/5] WORKDIR /app 0.0s
=> CACHED [react 3/5] COPY package*.json ./ 0.0s
=> CACHED [react 4/5] RUN npm install 0.0s
=> [react 5/5] COPY . . 0.5s
=> [react] exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:9ebfd4463af40681bafe16f2e4676938b1e58cfdd8323be570d88a39a672616e 0.0s
=> => naming to docker.io/library/local-react 0.0s
=> [react] resolving provenance for metadata file 0.0s
[+] Running 2/2
✔ react Built 0.0s
✔ Container local-react-1 Recreated 0.0s
Attaching to react-1
react-1 |
react-1 | > sample-react@0.0.0 dev
react-1 | > vite
react-1 |
react-1 |
react-1 | VITE v5.4.19 ready in 89 ms
react-1 |
react-1 | ➜ Local: http://localhost:5173/
react-1 | ➜ Network: http://172.21.0.2:5173/
うまくいってそう!!一応確認する。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0489acc9d69f local-react "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:3000->5173/tcp, [::]:3000->5173/tcp local-react-1
これで http://localhost:3000/ にもリクエストしてみると...
試しにsrc/main.tsを変更してみると、こんなログが!
react-1 | 6:30:55 PM [vite] page reload src/main.tsx
画面を確認。
リロードまで体感10秒〜15秒かかりました。
遅い理由はわかっていないですが、似た事例の記事を発見した。
いつか解消したい...。
【まとめ】
ホットリロードを有効化するには、以下のことが必要。
- docker-composeでボリュームマウントする
- 変更をコンテナ内部に反映させるため
- 以下のオプションを明示的に有効にする
CHOKIDAR_USEPOLLING=true
WATCHPACK_POLLING=true
【おまけ】
vite.config.ts
にホットリロードに必要な設定をした場合のものを置いておきます。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
// サーバがリッスンするホストとポートを設定
server: {
host: true,
port: 5173,
// ホットリロードのために必要なオプション値
watch: {
usePolling: true,
interval: 1000
}
},
})