fix(web): reload once when the module graph is aborted while booting
The lazy-route recovery cannot help when the browser aborts a module of the static import graph: nothing of the app runs, the root stays empty, and the only trace is a console error. A Web E2E run hit this right after a page reload, when four modules of the shell failed with net::ERR_NETWORK_CHANGED and the shell never rendered. An inline script in the HTML entry now listens for the error event of the module script and reloads the page once, guarded by a session flag that the entry module clears after a successful boot. The existing preload recovery stays in place; it only covers Vite's chunk preloads of production builds. A new E2E spec aborts one module request during boot and one lazy route request, and expects the sign-in page to render in both cases. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u (cherry picked from commit e5b7e036e1a60e7e270592c4b9382ee23ed45ccb)
This commit is contained in:
parent
99f868914a
commit
4b74ae3cc2
38
apps/web/e2e/module-recovery.spec.ts
Normal file
38
apps/web/e2e/module-recovery.spec.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import type { Page } from "@playwright/test";
|
||||||
|
import { expect, test } from "@playwright/test";
|
||||||
|
|
||||||
|
/** Abort the first request for a module once, then let every later request through. */
|
||||||
|
async function abortFirstRequest(page: Page, pattern: string) {
|
||||||
|
const counter = { aborted: 0 };
|
||||||
|
await page.route(pattern, async (route) => {
|
||||||
|
if (counter.aborted === 0) {
|
||||||
|
counter.aborted += 1;
|
||||||
|
await route.abort("failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await route.continue();
|
||||||
|
});
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
test("the app reloads itself once when a module request aborts while booting", async ({ page }) => {
|
||||||
|
const counter = await abortFirstRequest(page, "**/src/App.tsx");
|
||||||
|
|
||||||
|
await page.goto("/sign-in", { waitUntil: "commit" });
|
||||||
|
|
||||||
|
await expect(page.getByRole("heading", { name: "Sign in to EvOo" })).toBeVisible();
|
||||||
|
expect(counter.aborted).toBe(1);
|
||||||
|
expect(await page.evaluate(() => sessionStorage.getItem("rakazo:boot-reload"))).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("a lazy route recovers when its module request aborts", async ({ page }) => {
|
||||||
|
const counter = await abortFirstRequest(page, "**/src/pages/Auth.tsx");
|
||||||
|
|
||||||
|
await page.goto("/sign-in");
|
||||||
|
|
||||||
|
await expect(page.getByRole("heading", { name: "Sign in to EvOo" })).toBeVisible();
|
||||||
|
expect(counter.aborted).toBe(1);
|
||||||
|
expect(
|
||||||
|
await page.evaluate(() => sessionStorage.getItem("rakazo:module-reload:pages/Auth")),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
@ -29,6 +29,26 @@
|
|||||||
if (meta) meta.setAttribute("content", theme === "light" ? "#fafaf8" : "#07080a");
|
if (meta) meta.setAttribute("content", theme === "light" ? "#fafaf8" : "#07080a");
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
<script>
|
||||||
|
// Reload once when the browser aborts part of the module graph while the app
|
||||||
|
// boots (a network interface changed mid-request). main.tsx clears the flag
|
||||||
|
// after a successful boot; a second failure in a row is left to the browser.
|
||||||
|
addEventListener(
|
||||||
|
"error",
|
||||||
|
(event) => {
|
||||||
|
const target = event.target;
|
||||||
|
if (!(target instanceof HTMLScriptElement) || target.type !== "module") return;
|
||||||
|
try {
|
||||||
|
if (sessionStorage.getItem("rakazo:boot-reload")) return;
|
||||||
|
sessionStorage.setItem("rakazo:boot-reload", "1");
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@ -12,6 +12,10 @@ import { resolveUiLocale } from "./lib/ui-locale";
|
|||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
markOnce("rk:renderer:module-evaluated");
|
markOnce("rk:renderer:module-evaluated");
|
||||||
|
try {
|
||||||
|
// Set by the inline boot script in index.html before it reloads once.
|
||||||
|
sessionStorage.removeItem("rakazo:boot-reload");
|
||||||
|
} catch {}
|
||||||
installPreloadRecovery();
|
installPreloadRecovery();
|
||||||
applyUiDirection(resolveUiLocale());
|
applyUiDirection(resolveUiLocale());
|
||||||
applyUiAppearance();
|
applyUiAppearance();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user