Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 1x 1x 14x 12x 12x 10x 14x 6x 7x 6x 6x 7x 4x 5x 1x | // Self-heal stale tabs after a deploy.
//
// Astro fingerprints client JS/CSS as `/_astro/[hash].js`. Each deploy mints
// new hashes and deletes the old files. A tab opened before a deploy still
// references the old hashes; when it later soft-navigates (ClientRouter) or
// prefetches, the request for the now-deleted chunk 404s, the script fails to
// boot, and the page goes blank. One full reload fetches fresh HTML with
// current hashes and fixes it.
//
// Resource-load errors ('error' on a <script>/<link>) do NOT bubble, so we
// listen in the capture phase on window. The listener is registered once on
// import; window survives ClientRouter swaps, so it persists across SPA navs
// without needing `data-astro-rerun`.
const RELOAD_KEY = "__chunkReloadAt";
const RELOAD_COOLDOWN_MS = 10_000;
/**
* True only for a failed load of one of our own fingerprinted bundle assets
* (a <script>/<link> whose src/href contains `/_astro/`, regardless of
* origin). False for images, inline script errors, or elements with no URL.
*/
export function isStaleChunkError(target: EventTarget | null): boolean {
if (!(target instanceof Element)) return false;
const tag = target.tagName;
if (tag !== "SCRIPT" && tag !== "LINK") return false;
const url =
target.getAttribute("src") ?? target.getAttribute("href") ?? "";
return url.includes("/_astro/");
}
/**
* Register a capture-phase 'error' listener that reloads the page once when a
* fingerprinted `/_astro/*` asset 404s. A sessionStorage timestamp guards
* against reload storms: at most one reload per RELOAD_COOLDOWN_MS.
*/
export function installChunkReloadGuard(win: Window = window): void {
win.addEventListener(
"error",
(event) => {
if (!isStaleChunkError(event.target)) return;
// Loop-guard. sessionStorage can throw (Safari private mode); a
// failure to read/write must not swallow the reload — better to
// risk a rare extra reload than leave the user on a blank page.
try {
const last = Number(
win.sessionStorage.getItem(RELOAD_KEY) ?? "0",
);
if (Date.now() - last < RELOAD_COOLDOWN_MS) return;
win.sessionStorage.setItem(RELOAD_KEY, String(Date.now()));
} catch {
// ignore storage failures and fall through to reload
}
win.location.reload();
},
true,
);
}
installChunkReloadGuard();
|