🫠

webpackのruntimeChankでハマった

2024/06/21に公開

現象

react + webpackでwebアプリを作っている。
世間がreact19で騒いでいる中、今更ながらreact18にあげようと思った。
開発上ホットリロードは必須だが、react-hot-loaderはreact18に対応していないことがわかった。

https://github.com/gaearon/react-hot-loader/issues/1808

代わりにreact-refresh-webpack-pluginをいれてみた。

https://github.com/pmmmwh/react-refresh-webpack-plugin

npm install後、webpack.config.jsを編集して色々と設定していくが、ホットリロードがうまくいかない。
CMD + Sをすると、コンソール上の開発サーバーのログではビルドはされているように見えるが、画面上の更新がされない。

結論

以下を入れたら動いた。

webpack.config.js
module.exports = {
    ...
  optimization: {
    runtimeChunk: 'single',
  },
};

解説

チャンクについて

以下のようなファイルがある

./index.js
import app from './app.js';
./app.js
export default 'the app';

このようなファイルはwebpackによるバンドルを経て、チャンク(塊)と呼ばれるものに変換される。

https://zenn.dev/msy/articles/672488b7ed28a9

webpackで以下のような設定を行うことで、1つのchunkを生成することができる。

webpack.config.js
module.exports = {
    entry: './index.js' // ./index.jsをバンドルしたものをデフォルト名である「main」というchunkに出力する
};

チャンクは複数に分割することもでき、これをチャンク分割と言う。
webpackでは以下のような設定を行うことで、チャンク分割ができる。

webpack.config.js
module.exports = {
  entry: {
    home: './home.js',
    about: './about.js',
  },
};

optimization.runtimeChunkとは何をやっているのか

チャンクは依存解決とかがされたただのjsのコードなので、これをevalとかしてくれたりimport済みかどうかを管理してくれたりするwebpackの内部的なchunk(runtimeChunkという)が追加で作られる。

これをチャンク1つごとに追加のチャンクとして作るのがoptimization.runtimeChunk: 'multiple' or 'true'
逆にoptimization.runtimeChunk: 'single'とすると、全てのチャンクで使われる共通のチャンクが1個だけ作られる。

runtimeChunkはそれぞれがモジュールの読み込み済み状態を管理しているらしく、これにより、モジュールが複数回読み込まれたりしてしまうことがある。
そもそもjsのモジュールは読み込みに関して冪等であるべきだが、設計上仕方なくそうなっている場合もあるらしい。

ちなみにreact-refresh-webpack-pluginのリポジトリにも以下のようなことが書いてあった。

Only one copy of both the HMR runtime and the plugin's runtime should be embedded for one Webpack app
1つのWebpackアプリには、HMRのランタイムとプラグインのランタイムの両方のコピーを1つだけ埋め込む必要があります。

https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#component-not-updating-with-bundle-splitting-techniques

これらのことから、おそらくは今回のケースはruntimeChunkが複数作られ、何回も読み込みがされたことでホットリロードが動かなかったのだと思っている。

終わりに

viteにしたいね、ほんまに。

参考

https://www.wantedly.com/companies/wantedly/post_articles/298725

https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#component-not-updating-with-bundle-splitting-techniques

https://webpack.js.org/configuration/optimization/#optimizationruntimechunk

https://webpack.js.org/concepts/under-the-hood/#chunks

Discussion