発生した問題
Docker上でcreate-react-appを使用して環境構築を行ったところ、ソースコードを編集してもページが更新されない問題が発生しました。
また、ブラウザを更新しても編集内容はページに反映されません。
現時点(2022/4/29)では、日本語の記事で「Docker+Reactの環境構築でホットリロードが効かない場合、docker-compose.ymlと.envファイルで「CHOKIDAR_USEPOLLING=true」を設定すると解決する。」等、似たような問題が見つかりましたが、いずれも自分の環境では解決しませんでした。
使用した開発環境
開発に使用した環境は下記になります。
OS: Windows10 Pro
エディタ: VSCode
コンソール: powershell
パッケージマネージャ:Yarn
その他、依存関係は下記になります。
Docker: 20.10.14
Docker Compose: 2.4.1
yarn: 1.22.18
create-react-app:5.0.1
react: 18.1.0
react-dom: 18.1.0
react-scripts: 5.0.1
typescript: 4.6.4
問題の発生手順
ホスト側で下記ディレクトリ構成のファイルを用意します。
project/
├ docker-compose.yml
└ Dockerfile
version: "3.8"
services:
web:
build: .
volumes:
- .:/usr/src/app
command: sh -c "cd front && yarn start"
ports:
- 3000:3000
FROM node:16.15.0
WORKDIR /usr/src/app
ホスト側のdocker-compose.yml
のあるディレクトリに移動し、下記コマンドでプロジェクトを生成します。
docker-compose run --rm web `
sh -c "yarn create react-app front --template typescript"
プロジェクトが生成されたら、先ほどと同じ階層でwebコンテナを立ち上げる下記コマンドを実行します。
docker-compose up -d
webコンテナ上のサーバーの準備ができたらhttp://localhost:3000
にアクセスできることを確認します。
次に、ホスト側のApp.tsx
の内容を書き換えて保存してブラウザを更新しますが、編集内容は反映されません。
解決策
下記サイトを参考に、webpackのwatchOptionsの設定を上書きすることで解決したのでその手順を紹介します。
CRA 5.0 fails to hot-reload in a docker container built On shoulders of _____ #11879
setup.jsでwatchOptionsを上書きする手順
まずは、ホスト側のpackage.jsonにあるscripts
のstart
の定義を下記のように書き換えます。
"scripts": {
"start": "node ./setup && react-scripts start",
...
(CRA 5.0 fails to hot-reload in a docker container built On shoulders of _____ #11879より引用)
次に、ホスト側のfront
フォルダ直下にsetup.js
を作成し下記を記載します。
const fs = require('fs');
const path = require('path');
if (process.env.NODE_ENV === 'development') {
const webPackConfigFile = path.resolve('./node_modules/react-scripts/config/webpack.config.js');
let webPackConfigFileText = fs.readFileSync(webPackConfigFile, 'utf8');
if (!webPackConfigFileText.includes('watchOptions')) {
if (webPackConfigFileText.includes('performance: false,')) {
webPackConfigFileText = webPackConfigFileText.replace(
'performance: false,',
"performance: false,\n\t\twatchOptions: { aggregateTimeout: 200, poll: 1000, ignored: '**/node_modules', },"
);
fs.writeFileSync(webPackConfigFile, webPackConfigFileText, 'utf8');
} else {
throw new Error(`Failed to inject watchOptions`);
}
}
}
(CRA 5.0 fails to hot-reload in a docker container built On shoulders of _____ #11879より引用)
ホスト側のdocker-compose.yml
のある階層で、webコンテナを立ち上げる下記コマンドを実行します。
docker-compose up -d
webコンテナ上のサーバーの準備ができたらhttp://localhost:3000
にアクセスできることを確認します。
この時点で解決した報告がありますが、自分の場合はホスト側のApp.tsx
の内容を書き換えてブラウザを更新しても編集内容は反映されませんでした。
原因は、setup.jsの実行時点ではprocess.env.NODE_ENV
がundefined
になり、if (process.env.NODE_ENV === 'development') {...}
の条件式から抜けているためでした。
※下記のようにログを出力してsetup.js
の条件式に入る直前のprocess.env.NODE_ENV
の状態を確認しました。
const fs = require('fs');
const path = require('path');
console.log('process.env.NODE_ENV', process.env.NODE_ENV); //追加
...
なので、setup.js
を下記の通りコメントアウトしてみます。
const fs = require('fs');
const path = require('path');
// if (process.env.NODE_ENV === 'development') {
const webPackConfigFile = path.resolve('./node_modules/react-scripts/config/webpack.config.js');
let webPackConfigFileText = fs.readFileSync(webPackConfigFile, 'utf8');
if (!webPackConfigFileText.includes('watchOptions')) {
if (webPackConfigFileText.includes('performance: false,')) {
webPackConfigFileText = webPackConfigFileText.replace(
'performance: false,',
"performance: false,\n\t\twatchOptions: { aggregateTimeout: 200, poll: 1000, ignored: '**/node_modules', },"
);
fs.writeFileSync(webPackConfigFile, webPackConfigFileText, 'utf8');
} else {
throw new Error(`Failed to inject watchOptions`);
}
}
// }
次に、ホスト側のdocker-compose.yml
のある階層で、webコンテナを立ち上げる下記コマンドを実行します。
docker-compose restart
webコンテナ上のサーバーの準備ができたらhttp://localhost:3000
にアクセスできることを確認します。
画面が表示されたら、App.tsx
の内容を書き換えて保存すると、数秒遅れて画面が更新されることが確認できました。
一応、最終的なディレクトリ構成を載せておきます。
project/
├ front/
│ ├ node_modules/
│ ├ public/
│ ├ src/
│ ├ .gitignore
│ ├ package.json
│ ├ README.md
│ ├ setup.js
│ ├ tsconfig.json
│ ├ yarn.lock
├ docker-compose.yml
└ Dockerfile
参考
CRA 5.0 fails to hot-reload in a docker container built On shoulders of _____ #11879