remix: [Bug]: App crash on fast browser navigation
What version of Remix are you using?
1.1.3
What version of Node are you using? Minimum supported version is 14.
16.0.0
Steps to Reproduce
- Create a new Remix app with
npx create-remix@latest. - Choose the Remix dev server.
- Install dependencies using
yarn install. - Next to
app/routes/index.tsx, addapp/routes/other.tsxwith a component that simply renders<>Other</> - In
app/routes/index.tsx, add<Link to="/other">Other</Link>somewhere, withimport { Link } from "remix";. - Run your app using
yarn devoryarn start; the error happens for both dev and prod builds. - Open your browser and create a new browser tab (the bug happens with both Firefox and Chrome).
- Go to your app’s URL.
- Click the link to
Other. - Click the browser back button two times. The tab should now show your browser’s default UI for new tabs.
- Now very quickly click the browser’s forward button twice.
- The app should now crash. If it doesn’t you didn’t click the forward button fast enough.
Expected Behavior
The page content should be displayed without any errors.
Actual Behavior
In the simple repo above, the app crashes and there is the following stack trace in the dev console. In my real app in a production build, this issue then causes #1678, basically making the entire browser tab unresponsive.
components.js:470 Uncaught TypeError: Cannot read properties of undefined (reading 'meta')
at Meta (components.js:470:21)
at renderWithHooks (react-dom.development.js:14985:18)
at mountIndeterminateComponent (react-dom.development.js:17811:13)
at beginWork (react-dom.development.js:19049:16)
at HTMLUnknownElement.callCallback2 (react-dom.development.js:3945:14)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:16)
at invokeGuardedCallback (react-dom.development.js:4056:31)
at beginWork$1 (react-dom.development.js:23964:7)
at performUnitOfWork (react-dom.development.js:22776:12)
at workLoopSync (react-dom.development.js:22707:5)
Meta @ components.js:470
renderWithHooks @ react-dom.development.js:14985
mountIndeterminateComponent @ react-dom.development.js:17811
beginWork @ react-dom.development.js:19049
callCallback2 @ react-dom.development.js:3945
invokeGuardedCallbackDev @ react-dom.development.js:3994
invokeGuardedCallback @ react-dom.development.js:4056
beginWork$1 @ react-dom.development.js:23964
performUnitOfWork @ react-dom.development.js:22776
workLoopSync @ react-dom.development.js:22707
renderRootSync @ react-dom.development.js:22670
performSyncWorkOnRoot @ react-dom.development.js:22293
scheduleUpdateOnFiber @ react-dom.development.js:21881
updateContainer @ react-dom.development.js:25482
(anonymous) @ react-dom.development.js:26021
unbatchedUpdates @ react-dom.development.js:22431
legacyRenderSubtreeIntoContainer @ react-dom.development.js:26020
hydrate2 @ react-dom.development.js:26086
(anonymous) @ entry.client.tsx:4```
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 13
- Comments: 23 (13 by maintainers)
Commits related to this issue
- Add repro case for issue 1757 https://github.com/remix-run/remix/issues/1757 — committed to n8agrin/remix by n8agrin a year ago
- fix: reload page when routeModules doesn't contain module for current route This can happen when entry.client.ts isn't fully loaded before a route change occurs. See https://github.com/remix-run/rem... — committed to n8agrin/remix by n8agrin a year ago
I think I’m gonna call this the goldilocks bug. It’s not just an issue of clicking too fast, or too slow. It seems to happen if you click forward, then wait just the right amount of time for the modules to start loading for
index.tsxand then click the forward button a second time during the index chunk loads.I could never reproduce it normally, but once I turned on network throttling and waited long enough to see the
.jsfiles start loading I could reproduce it.I believe this is what’s happening:
/(index route) on the serverpopstateis ignored since we haven’t finished loading the chunks yet and therefore haven’t instantiated our client side router and it’spopstatelistener/othersince that’s the current URLA few off-the-cuff options:
/other/otherchunks and delay hydration until they complete. That introduces the case for the same issue on a third click, so that would have to do the check each time the new “initial” route chunks load.I prefer 1 😃
A similar error occurred when I stupidly rendered
<Scripts/>twice inroot.tsx. Maybe this is helpful for someone.components:js:
The error occurs only on
<Link/>navigation. On refresh the route loads fine.I’m running into this as well.
A trivial repro is:
hypothesis:
/joinwhich is not part of the routeModules map and it blows uphypothetical fix:
Running into the same issue caused by fast navigation between pages
This seems to be caused by a race condition in the Remix code.
As far as I understand, the
loadRouteModulefunction inrouteModules.tsloads the JavaScript file related to a route and then adds an entry to therouteModulescache.The
Metacomponent uses this cache to do its thing.If you’re doing the browser navigation slowly, everything works as expected:
loadRouteModuleloads the JS file, updates the cache and only then doesMetatry to use it. If you’re fast, however,loadRouteModulehasn’t updated therouteModulescache yet, butMetatries to access it anyway, resulting in the observed crash.I’m not sure how to fix this, the code that is involved is quite… complicated and I’ve not yet been able to completely understand it.