Getting HMR / Fast Refresh to work on old browsers with create-react-app v4

Looking for the quick solution? Go to the TL;DR!

Last week, I discovered an old iPad 2 lying around. Also being the proud owner of a 3D printer, I quickly printed a holder for my wall and placed the iPad in there. Good! Now, let’s create a web-app for it so I can make a nice wall display, displaying whatever I want.

So, naturally, I ran yarn create react-app ipad-wall (equivalent of npx create-react-app ipad-wall) and began writing some code. After a short 5 minutes, I wanted to see it run on the iPad, so I pointed Safari to my local IP. But there I was met with a white screen…

My first thought was that I should edit the browserslist section of package.json; after all, this is a very old device and the javascript must be transpiled to ES5 to even be considered by the old browser. So, I copied the “production” part to the “development” part (because it’s the dev server) and I added “iOS 9”, like so:

"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all",
"iOS 9"
],
"development": [
">0.2%",
"not dead",
"not op_mini all",
"iOS 9"
]
}

After re-running the dev server (yarn start), and refreshing the iPad… still a white screen. All right, time to get out the debugging tools…
I attached my iPad to my Macbook and ran the remote javascript terminal to see what the error could be.

The error

The error that my iPad gave me confused me for a while:
SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode. (main.chunk.js:216)
I thought we even defined “iOS 9” in “development” to browserslist? Looking at main.chunk.js, we find the following chunk of code:

[...]
const isHotUpdate = !!module.hot.data;
const prevExports = isHotUpdate ? module.hot.data.prevExports : null;
[...]

What are const declarations doing there?!
Well, I’m here to tell you.

The cause

As it turns out, this part of the code is hot-injected into the page at runtime and thus are not transpiled by babel / browserslist.
There currently is an issue for this in the corresponding plugin (@pmmmwh/react-refresh-webpack-plugin) over here: https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/297, but there doesn’t seem to be much going on at the moment.

The solution

So, I took it upon myself to try and fix this. My solution was as follows:

"resolutions": {
"@pmmmwh/react-refresh-webpack-plugin": "https://github.com/jeffhuys/react-refresh-webpack-plugin.git#main"
}
  • I removed node_modules and ran yarn again to fetch the packages, but this time substituting the original package for my own one
  • Ran yarn start again
  • No more error! Fast Refresh (aka Hot Module Reloading / HMR) works again!

TL;DR

If you want to quickly solve this issue for yourself, add the following to your package.json:

"resolutions": {
"@pmmmwh/react-refresh-webpack-plugin": "https://github.com/jeffhuys/react-refresh-webpack-plugin.git#main"
}

Then remove node_modules and re-install.

The caveat

The resolutions entry in package.json is only supported in yarn as far as I know. There is a PR for this for npm (https://github.com/npm/rfcs/pull/129), but I’m unsure of the progress. Manually modifiying package-lock.json might be a semi-solution.