fix(boot): auto-recover from stale chunks after a deploy

Deploys replace hashed chunk filenames; a tab that was already open can load a
chunk that no longer exists (404) and hit the error boundary ('THIS PAGE
SLAMMED'). Listen for Vite's vite:preloadError (and dynamic-import failures) and
reload once, guarded against loops.
This commit is contained in:
SkateSpots 2026-09-26 17:33:20 +07:00
parent b6c33c8a9b
commit d24e963fd9

View file

@ -76,6 +76,40 @@ import '@fontsource/barlow-condensed/700.css';
})(); })();
/**
* STALE-DEPLOY SELF-HEAL
*
* Deploys replace hashed chunk filenames and delete the old ones. A tab that
* was already open still holds the previous manifest, so navigating to a lazy
* route loads a chunk that no longer exists (404) and the error boundary shows
* "THIS PAGE SLAMMED". Vite emits `vite:preloadError` for exactly this case.
*
* Reload once to pick up the new assets. The timestamp guard prevents a reload
* loop if a build is genuinely broken (the error boundary will show instead).
*/
(function recoverFromStaleChunks() {
const KEY = 'skatespots:chunk-reload-at';
const reload = () => {
try {
const last = Number(sessionStorage.getItem(KEY) || 0);
if (Date.now() - last < 15000) return; // already reloaded recently — don't loop
sessionStorage.setItem(KEY, String(Date.now()));
} catch {
/* sessionStorage unavailable — fall through and reload anyway */
}
window.location.reload();
};
window.addEventListener('vite:preloadError', reload);
window.addEventListener('unhandledrejection', (e) => {
const msg = String((e as PromiseRejectionEvent).reason?.message ?? '');
if (/dynamically imported module|Importing a module script failed|Loading chunk/i.test(msg)) {
reload();
}
});
})();
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<ErrorBoundary> <ErrorBoundary>
<App /> <App />