Laravel on Docker環境でWebpackのHMRが効かないケースへの対応
- Webpack
- Docker
- Laravel
MPA構成のHMR指定に地味な点でこれまで何度かハマってしまったため自分用に備忘録を残しておく。
環境
- webpack@5.74.0 (非mix)
- webpack-dev-server@4.7.4
- webpack-cli@4.10.0
確認すべき事
dev-serverのHMRオプションが本当に有効になっているか
config上、hot: true
を指定しても有効にならないケースがある。これは、おそらく公式ドキュメントに記載されている下記の仕様が関係しており、環境によりHotModuleReplacementPlugin
が正常にロードされない場合に無効となるようだ。
Since webpack-dev-server v4, HMR is enabled by default. It automatically applies webpack.HotModuleReplacementPlugin which is required to enable HMR. So you don't have to add this plugin to your webpack.config.js when hot is set to true in config or via the CLI option --hot. See the HMR concepts page for more information.
現在の状態は、アプリケーション立ち上げ後にコンソール上に表示されるログで確認できる。
[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading disabled, Progress disabled, Overlay enabled.
もしHot Module Replacement disabled
となっている場合には、—-hot
オプションを付与することで自動的にプラグインが追加される。
リバースプロキシの設定を忘れていないか
ホスト/コンテナ間でHMRを通すためWeb用に作成しているコンテナで開発サーバーのポートを内部通せるようになっている、または空けているポートと設定が間違っていないかを確認し、設定が抜けている場合、docker-composeで対象コンテナに<dev-server-port>:<web-port>
を指定。(devServerとコンテナのportは重複しないようにする)
例:
web:
build:
...
ports:
- '3081:8080'
変更を検知させようとしているファイルが正しく import されているか
Entryポイントかその範囲下でロード出来ていない場合など、Nothing hot updated.
となる。
publicPath
の指定が振り分けられているか
webpack.config.js、bladeそれぞれ、開発時は開発サーバーに向ける。
isDev ? 'http://localhost:3000' : '/'
http://localhost:3000/js/app.js
最終的な設定
- Webコンテナのport設定を
3081:8080
とした場合 - blade更新時のリロードを無効とする場合、明示的に
liveReload: false
も指定しておく
devServer: {
host: 'localhost',
port: '3000',
client: {
overlay: true,
webSocketURL: 'ws://localhost:3000/ws',
},
proxy: {
'*': 'http://0.0.0.0:3081/',
},
hot: 'only',
liveReload: false,
static: {
directory: path.resolve(__dirname, 'path-to-laravel/public'),
},
devMiddleware: {
writeToDisk: true,
publicPath: 'http://localhost:3000/',
},
watchFiles: [
'path-to-laravel/resources/**/*.blade.php',
'path-to-laravel/public/css/*.css',
'path-to-laravel/public/js/*.js',
],
},
補足
- CORSの設定は必要に応じて、
allowedHosts
、headers
で行う static
はWebpack@4のcontentBase
と同様hot: 'only'
は、ビルド失敗時のページ更新を無効とする設定。(ドキュメント)
追記('22, 8/31)
HMRによる更新時 output.path
に、変更を通知するため[name].[hash].hot-update.[ext]
ファイルが出力される。
上記の構成のままではcssやjsの hot-update が出力され続けてしまうため、下記のように対応する。
Webpack 4系
※ rimraf 等を使い hot
配下を削除するような処理を任意の方法で作っておく事
module.exports = {
...
output: {
...
hotUpdateChunkFilename: 'hot/hot-update.js',
hotUpdateMainFilename: 'hot/hot-update.json',
},
}
Webpack 5系
5のリリース以降、hotUpdate*系のオプションが廃止されたというドキュメントは見つけられていないが、v5.74.0 では対応されていなかったためevent-hooks-webpack-pluginを使い対処する。
参考:Webpack 5 リリース (2020-10-10)
※ rimraf のcallback関数が未指定だとWebpackの処理が止まるため、空の関数を入れている
const rimraf = require('rimraf');
const EventHooksPlugin = require('event-hooks-webpack-plugin');
module.exports = {
...
plugins: [
...
new EventHooksPlugin({
afterCompile: () => {
rimraf('path-to-laravel/public/**/*.hot-update.json', () => {});
rimraf('path-to-laravel/public/**/*.hot-update.js', () => {});
rimraf('path-to-laravel/public/**/*.hot-update.js.map', () => {});
},
}),
],
}
これで、hot-update ファイルが増え続ける状態はひとまず解消される