Docker環境でwebpack-dev-serverのホットリロードが動かないときの対処法
久しぶりにDockerコンテナの中にwebpackを導入する機会があったのですが、その際webpack-dev-serverのホットリロードが動かず若干つまづいたので、その時の対処方法をメモとして残すことにしました。
つまづいたこと
タイトル通りなのですが、以下のようなコードを書いて、Dockerコンテナでwebpack-dev-serverを動かそうと試みたのですが、ホットリロードができませんでした。
→手動リロードを行うことで、コードの変更は確認できましたが、とてもじゃないけど面倒臭くてやってられないです。。。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
watch: true,
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: './index.html',
template: path.resolve(__dirname, 'dist/index.html'),
}),
],
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
hot: true,
open: true,
port: 8080,
host: '0.0.0.0',
historyApiFallback: true,
},
resolve: {
extensions: ['.js', '.ts', '.tsx']
},
}
version: '3'
services:
front:
container_name: front
build: ./docker/front
tty: true
volumes:
- ./front:/front
ports:
- 8080:8080
command: yarn run start
docker-compose up -d
でDockerコンテナを立ち上げた時に、yarn run start
でwebpack-dev-serverを起動するという割とシンプルなコードです。
docker logsでコンテナのログを見てもサーバーの立ち上げやコンパイルの失敗したようなエラーメッセージなどは表示されておらず、若干つまづきました。
ちなみに、yarn run startで以下のようなコマンドが実行される想定です。
webpack-dev-server --config webpack.config.js
解決策
結論から言うと、Dockerコンテナの中でwebpack-dev-serverのホットリロードを有効にするためには、オプションでポーリング(主となるシステムが他のシステムに変更がないか一定の間隔で要求がないか尋ねること)を行うように設定する必要があるそうです。
→公式のめっちゃ目立つところに、watchが適切に機能しない場合はこのページを見てくださいと思いっきり書いてありましたw
https://webpack.js.org/configuration/watch/
webpackの公式には、こんなことも書いてありました。
If watching does not work for you, try out this option. Watching does not work with NFS and machines in VirtualBox.
https://webpack.js.org/configuration/watch/#watchoptionsaggregatetimeout
Dockerコンテナの中はホストOSとは隔離された空間(ファイルシステム)なので、それが原因で動かなかったという感じでしょうか?
おそらくこれで間違い無いと思い、先ほどのwebpack.config.js
を以下のように変更してみました。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
watch: true,
// 追加
watchOptions: {
// 最初の変更からここで設定した期間に行われた変更は1度の変更の中で処理が行われる
aggregateTimeout: 200,
// ポーリングの間隔
poll: 1000
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: './index.html',
template: path.resolve(__dirname, 'dist/index.html'),
}),
],
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
hot: true,
open: true,
port: 8080,
host: '0.0.0.0',
historyApiFallback: true,
},
resolve: {
extensions: ['.js', '.ts', '.tsx']
},
}
ポーリングを行うオプションを追加したら、無事ホットリロードが行われるようになりました。
調べる過程で、ポーリングとかファイルシステムとかOSに関連するワードがいくつか出てきたので、調べるきっかけにはなりました。
つまづきはしましたが、結果オーライって感じです。
Next.jsの場合
ちなみにですが、Next.jsの場合はこんな感じで書いたらホットリロードが効くようになりました。
module.exports = {
webpack: (config, { dev }) => {
if (dev) {
config.watchOptions = {
poll: 1000,
aggregateTimeout: 200,
};
}
return config;
},
};
devは、コンパイルが開発環境で行われているかどうかをブーリアンで返すので、開発環境でNext.jsのアプリケーションが実行されている時のみポーリングを行うイメージです。
https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config
まとめ
まとめです。
- webpack-dev-serverのホットリロードをDockerコンテナの中で行うには一工夫必要
- ポーリング・・・主となるシステムが他のシステムに変更がないか一定の間隔で要求がないか尋ねること
- ファイルシステム・・・記憶装置に保存されたデータを管理し操作するために必要な機能のこと
おまけ
最近は、こっそりReact + puppeteer + Lambdaを用いたウェブアプリケーションの開発を行っています。
個人開発としては、カルキチブログ以来のそこそこガチなやつです。
それについても今後書いていけたらなと思っています。
後、開発とは全く関係ありませんが、ここ3〜4週間くらいですでに2回ほど体調をぶっ壊しています。
気温の変化に順応できませんでした。
皆さんも体調は管理は気をつけて、頑張っていきましょう。。