| 1 | // Split chunks are fetched lazily, so a deploy (or desktop server swap) |
| 2 | // between page load and a later fetch can 404 the old hashed assets. One |
| 3 | // reload picks up the fresh index.html. A sessionStorage flag keeps a |
| 4 | // persistent failure from becoming a reload loop, and a successful boot clears |
| 5 | // it so the next stale deploy gets its own single reload. |
| 6 | const CHUNK_RELOAD_GUARD_KEY = "t3code:chunk-load-reloaded"; |
| 7 | |
| 8 | /** |
| 9 | * Called from the `vite:preloadError` listener. Reloads at most once per |
| 10 | * failure streak and returns whether it did, so the caller knows whether to |
| 11 | * swallow the event or let the error surface through the normal paths. |
| 12 | */ |
| 13 | export function reloadOnceForChunkLoadError( |
| 14 | getStorage: () => Storage = () => window.sessionStorage, |
| 15 | reload: () => void = () => window.location.reload(), |
| 16 | ): boolean { |
| 17 | let alreadyReloaded: boolean; |
| 18 | try { |
| 19 | const storage = getStorage(); |
| 20 | alreadyReloaded = storage.getItem(CHUNK_RELOAD_GUARD_KEY) === "1"; |
| 21 | if (!alreadyReloaded) storage.setItem(CHUNK_RELOAD_GUARD_KEY, "1"); |
| 22 | } catch { |
| 23 | // Without storage the guard cannot survive a reload, so a persistent |
| 24 | // failure would loop forever. Let the error surface instead. |
| 25 | return false; |
| 26 | } |
| 27 | if (alreadyReloaded) return false; |
| 28 | reload(); |
| 29 | return true; |
| 30 | } |
| 31 | |
| 32 | /** Clears the guard after a successful boot so a later stale deploy can reload again. */ |
| 33 | export function clearChunkReloadGuard(getStorage: () => Storage = () => window.sessionStorage) { |
| 34 | try { |
| 35 | getStorage().removeItem(CHUNK_RELOAD_GUARD_KEY); |
| 36 | } catch { |
| 37 | // Blocked storage never held the flag. |
| 38 | } |
| 39 | } |