Classic React production bug: you deploy a new bundle, user has the old HTML cached in their tab, they navigate to a route → React.lazy() tries to import a chunk that no longer exists on the CDN → blank screen.
The error in the console looks like:
Failed to fetch dynamically imported module:
https://cdn.example.com/assets/Page-abc123.js
The user has no way out except hard-reload, and most don't know that.
The fix
A global error listener that catches chunk load errors and force-reloads the page with a cache-bust param:
js
const CHUNK_ERROR_PATTERNS = [
/Loading chunk \d+ failed/i,
/Failed to fetch dynamically imported module/i,
/Loading CSS chunk .* failed/i,
/Importing a module script failed/i,
];
window.addEventListener('error', (e) => {
const msg = e?.message || '';
if (CHUNK_ERROR_PATTERNS.some(rx => rx.test(msg))) {
const url = new URL(window.location.href);
url.searchParams.set('_r', String(Date.now()));
window.location.replace(url.toString());
}
});
Why each part matters:
Multiple patterns: different browsers throw different messages. Safari uses "Importing a module script failed", Chrome uses "Failed to fetch dynamically imported module", older Webpack builds use "Loading chunk N failed".
Case insensitive: some browsers capitalize, some don't.
Cache-bust param: ?_r=<timestamp> forces fresh index.html, which has the new chunk hashes.
replace() not assign(): doesn't add a history entry, so back button works.
Gotchas
This catches unhandledrejection too if the lazy import throws inside a promise. Add a second listener if you see misses.
Don't trigger reload more than once: add a flag to avoid loops on a network outage.
Test it: deploy a new build, open the old tab, navigate. Should auto-recover.
It's 15 lines but saved me a real percentage of users abandoning the app post-deploy.
Top comments (0)