Skip to content

Commit

Permalink
Properly handle interrupted __manifest requests in lazy route discove…
Browse files Browse the repository at this point in the history
…ry (#10447)
brophdawg11 authored Jan 30, 2025
1 parent 6f6f8d2 commit aae1aae
Showing 9 changed files with 118 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/dull-files-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/react": patch
---

Properly handle interrupted \_\_manifest requests in lazy route discovery
62 changes: 62 additions & 0 deletions integration/fog-of-war-test.ts
Original file line number Diff line number Diff line change
@@ -1448,4 +1448,66 @@ test.describe("Fog of War", () => {
),
]);
});

test("handles interruptions from back to back navigations", async ({
page,
}) => {
let fixture = await createFixture({
config: {
future: {
v3_lazyRouteDiscovery: true,
},
},
files: {
...getFiles(),
"app/routes/a.tsx": js`
import { Link, Outlet, useLoaderData, useNavigate } from "@remix-run/react";
export function loader({ request }) {
return { message: "A LOADER" };
}
export default function Index() {
let data = useLoaderData();
let navigate = useNavigate();
return (
<>
<h1 id="a">A: {data.message}</h1>
<button data-link onClick={async () => {
navigate('/a/b');
setTimeout(() => navigate('/a/b'), 0)
}}>
/a/b
</button>
<Outlet/>
</>
)
}
`,
},
});
let appFixture = await createAppFixture(fixture);
let app = new PlaywrightFixture(appFixture, page);

await app.goto("/a", true);
expect(
await page.evaluate(() =>
Object.keys((window as any).__remixManifest.routes)
)
).toEqual(["root", "routes/a", "routes/_index"]);

// /a/b gets discovered on click
await app.clickElement("[data-link]");
await new Promise((resolve) => setTimeout(resolve, 1000));
expect(await (await page.$("body"))?.textContent()).not.toContain(
"Not Found"
);
await page.waitForSelector("#b");

expect(
await page.evaluate(() =>
Object.keys((window as any).__remixManifest.routes)
)
).toEqual(["root", "routes/a", "routes/_index", "routes/a.b"]);
});
});
2 changes: 1 addition & 1 deletion integration/package.json
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
"@remix-run/dev": "workspace:*",
"@remix-run/express": "workspace:*",
"@remix-run/node": "workspace:*",
"@remix-run/router": "1.21.2-pre-v6.0",
"@remix-run/router": "1.22.0-pre-v6.1",
"@remix-run/server-runtime": "workspace:*",
"@types/express": "^4.17.9",
"@vanilla-extract/css": "^1.10.0",
2 changes: 1 addition & 1 deletion packages/remix-dev/package.json
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@
"@mdx-js/mdx": "^2.3.0",
"@npmcli/package-json": "^4.0.1",
"@remix-run/node": "workspace:*",
"@remix-run/router": "1.21.2-pre-v6.0",
"@remix-run/router": "1.22.0-pre-v6.1",
"@remix-run/server-runtime": "workspace:*",
"@types/mdx": "^2.0.5",
"@vanilla-extract/integration": "^6.2.0",
28 changes: 18 additions & 10 deletions packages/remix-react/fog-of-war.ts
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ export function getPatchRoutesOnNavigationFunction(
if (!isFogOfWarEnabled(future, isSpaMode)) {
return undefined;
}
return async ({ path, patch }) => {
return async ({ path, patch, signal }) => {
if (discoveredPaths.has(path)) {
return;
}
@@ -85,7 +85,8 @@ export function getPatchRoutesOnNavigationFunction(
future,
isSpaMode,
basename,
patch
patch,
signal
);
};
}
@@ -207,7 +208,8 @@ export async function fetchAndApplyManifestPatches(
future: FutureConfig,
isSpaMode: boolean,
basename: string | undefined,
patchRoutes: Router["patchRoutes"]
patchRoutes: Router["patchRoutes"],
signal?: AbortSignal
): Promise<void> {
let manifestPath = `${basename ?? "/"}/__manifest`.replace(/\/+/g, "/");
let url = new URL(manifestPath, window.location.origin);
@@ -222,15 +224,21 @@ export async function fetchAndApplyManifestPatches(
return;
}

let res = await fetch(url);
let serverPatches: AssetsManifest["routes"];
try {
let res = await fetch(url, { signal });

if (!res.ok) {
throw new Error(`${res.status} ${res.statusText}`);
} else if (res.status >= 400) {
throw new Error(await res.text());
}
if (!res.ok) {
throw new Error(`${res.status} ${res.statusText}`);
} else if (res.status >= 400) {
throw new Error(await res.text());
}

let serverPatches = (await res.json()) as AssetsManifest["routes"];
serverPatches = (await res.json()) as AssetsManifest["routes"];
} catch (e) {
if (signal?.aborted) return;
throw e;
}

// Patch routes we don't know about yet into the manifest
let knownRoutes = new Set(Object.keys(manifest.routes));
6 changes: 3 additions & 3 deletions packages/remix-react/package.json
Original file line number Diff line number Diff line change
@@ -19,10 +19,10 @@
"tsc": "tsc"
},
"dependencies": {
"@remix-run/router": "1.21.2-pre-v6.0",
"@remix-run/router": "1.22.0-pre-v6.1",
"@remix-run/server-runtime": "workspace:*",
"react-router": "6.28.3-pre-v6.1",
"react-router-dom": "6.28.3-pre-v6.1",
"react-router": "6.29.0-pre-v6.2",
"react-router-dom": "6.29.0-pre-v6.2",
"turbo-stream": "2.4.0"
},
"devDependencies": {
2 changes: 1 addition & 1 deletion packages/remix-server-runtime/package.json
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
"tsc": "tsc"
},
"dependencies": {
"@remix-run/router": "1.21.2-pre-v6.0",
"@remix-run/router": "1.22.0-pre-v6.1",
"@types/cookie": "^0.6.0",
"@web3-storage/multipart-parser": "^1.0.0",
"cookie": "^0.6.0",
4 changes: 2 additions & 2 deletions packages/remix-testing/package.json
Original file line number Diff line number Diff line change
@@ -21,8 +21,8 @@
"dependencies": {
"@remix-run/node": "workspace:*",
"@remix-run/react": "workspace:*",
"@remix-run/router": "1.21.2-pre-v6.0",
"react-router-dom": "6.28.3-pre-v6.1"
"@remix-run/router": "1.22.0-pre-v6.1",
"react-router-dom": "6.29.0-pre-v6.2"
},
"devDependencies": {
"@remix-run/server-runtime": "workspace:*",
50 changes: 25 additions & 25 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit aae1aae

Please sign in to comment.