React+Electron+webpack編成にHMR入れる
READMEが丁寧で基本十分なのだが、ハマった部分があったことや日本語情報が少ないので一応書き残す。
あとReactではHMRじゃなくてFast Refreshという感じらしい。
必要な依存を入れる
code:sh
yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh type-fest webpack webpack-cli webpack-dev-server
code:webpack.config.ts
import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin"
...略...
const babelLoaderConfiguration: (b: boolean) => webpack.RuleSetRule = (
isDev
) => ({
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
presets: [
"@babel/preset-typescript",
"@babel/preset-react",
],
plugins: [
isDev && "react-refresh/babel",
...略...
].filter((s) => s),
...略...
const isDev = args.mode !== "production"
return {
...略...
devServer: {
hot: isDev,
devMiddleware: { publicPath: "/dist" },
static: {
directory: __dirname,
watch: false,
},
port: 10170,
},
plugins: [
...略...
isDev ? new ReactRefreshWebpackPlugin() : (undefined as never),
].filter((p: unknown) => p),
...略...
...略...入れすぎてよくわからなくなってしまった
publicPath
/rinsuki/rinsuki.iconに助言いただきました
distにmain.{js,css}を吐き出していた編成なので、devMiddlewarwe.publicPathでそのパスから読み取れるようにし、index.htmlやassetsのためルートディレクトリをstatic.directoryを有効化する。ただ、ルートディレクトリのwatchを見ていては関係ない変更でリロードされてしまうし、今回はHMRなのでwatchは無効化する。
noParse
module.noParseで指定しているモジュールにはreact-refresh/babelが適用されず、__react_refresh_util is not definedとなるので、なんとかする
今回はimportを残したいだけだったのでimport(/* webpackIgnore: true */ s)にして解決したが、他の使い方をしている場合ちょっと困りそう
https://gyazo.com/ffdf84abc294102d04729058254a9f87
file://だったら見逃してくれるCORSが全部引っかかるようになる
ここを参考にヘッダーを書き換える
が、CORSは同じヘッダーがダブルで宣言されてると落ちてしまうので、ちょっと気を利かせる
code:ts
window.webContents.session.webRequest.onHeadersReceived(
(details, callback) => {
const responseHeaders = details.responseHeaders || {}
const keys = Object.keys(responseHeaders)
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": Authorization",
"Access-Control-Allow-Methods": "*", "Access-Control-Allow-Credentials": "true", })) {
if (!keys.includes(key.toLowerCase())) {
responseHeaderskey = value }
}
callback({ responseHeaders })
}
)