diff --git a/web/src/lib/reloadOnPreloadError.test.ts b/web/src/lib/reloadOnPreloadError.test.ts index f17990e8..e96763d7 100644 --- a/web/src/lib/reloadOnPreloadError.test.ts +++ b/web/src/lib/reloadOnPreloadError.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { installPreloadErrorReload } from "./reloadOnPreloadError"; function harness(now: () => number) { @@ -16,9 +16,16 @@ function harness(now: () => number) { } describe("installPreloadErrorReload", () => { + let cleanups: Array<() => void> = []; + + afterEach(() => { + cleanups.forEach((cleanup) => cleanup()); + cleanups = []; + }); + it("reloads when a dynamically imported chunk fails to load", () => { const { reload, deps } = harness(() => 1_000_000); - installPreloadErrorReload(deps); + cleanups.push(installPreloadErrorReload(deps)); window.dispatchEvent(new Event("vite:preloadError")); expect(reload).toHaveBeenCalledTimes(1); @@ -28,14 +35,14 @@ describe("installPreloadErrorReload", () => { let clock = 1_000_000; const { reload, deps } = harness(() => clock); - installPreloadErrorReload(deps); + cleanups.push(installPreloadErrorReload(deps)); window.dispatchEvent(new Event("vite:preloadError")); expect(reload).toHaveBeenCalledTimes(1); // Post-reload page still hits the error seconds later: give up instead // of reload-looping. clock += 5_000; - installPreloadErrorReload(deps); + cleanups.push(installPreloadErrorReload(deps)); window.dispatchEvent(new Event("vite:preloadError")); expect(reload).toHaveBeenCalledTimes(1); }); @@ -44,12 +51,12 @@ describe("installPreloadErrorReload", () => { let clock = 1_000_000; const { reload, deps } = harness(() => clock); - installPreloadErrorReload(deps); + cleanups.push(installPreloadErrorReload(deps)); window.dispatchEvent(new Event("vite:preloadError")); expect(reload).toHaveBeenCalledTimes(1); clock += 10 * 60_000; - installPreloadErrorReload(deps); + cleanups.push(installPreloadErrorReload(deps)); window.dispatchEvent(new Event("vite:preloadError")); expect(reload).toHaveBeenCalledTimes(2); }); diff --git a/web/src/lib/reloadOnPreloadError.ts b/web/src/lib/reloadOnPreloadError.ts index 288fd42c..c41a9322 100644 --- a/web/src/lib/reloadOnPreloadError.ts +++ b/web/src/lib/reloadOnPreloadError.ts @@ -15,13 +15,13 @@ interface PreloadErrorReloadDeps { setItem: (key: string, value: string) => void; } -export function installPreloadErrorReload(deps?: Partial): void { +export function installPreloadErrorReload(deps?: Partial): () => void { const reload = deps?.reload ?? (() => window.location.reload()); const now = deps?.now ?? Date.now; const getItem = deps?.getItem ?? ((k: string) => sessionStorage.getItem(k)); const setItem = deps?.setItem ?? ((k: string, v: string) => sessionStorage.setItem(k, v)); - window.addEventListener("vite:preloadError", (event) => { + const handler = (event: Event) => { const lastReloadAt = Number(getItem(GUARD_KEY) ?? 0); if (now() - lastReloadAt < GUARD_WINDOW_MS) { // We already reloaded moments ago and the chunk is still missing; @@ -31,5 +31,8 @@ export function installPreloadErrorReload(deps?: Partial event.preventDefault(); setItem(GUARD_KEY, String(now())); reload(); - }); + }; + + window.addEventListener("vite:preloadError", handler); + return () => window.removeEventListener("vite:preloadError", handler); }