Skip to content

Commit

Permalink
Fix fog of war hydration in SSR apps that matched a splat route on th…
Browse files Browse the repository at this point in the history
…e server (#11790)
  • Loading branch information
brophdawg11 authored Jul 10, 2024
1 parent da65120 commit 9e1da44
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/wicked-ducks-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/router": patch
---

Fix fog of war hydration in SSR apps that matched a splat route on the server
35 changes: 33 additions & 2 deletions packages/router/__tests__/lazy-discovery-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ describe("Lazy Route Discovery (Fog of War)", () => {
]);
});

it("discovers routes during initial hydration when a splat route matches", async () => {
it("discovers routes during initial SPA renders when a splat route matches", async () => {
let childrenDfd = createDeferred<AgnosticDataRouteObject[]>();

router = createRouter({
Expand All @@ -669,7 +669,7 @@ describe("Lazy Route Discovery (Fog of War)", () => {
path: "*",
},
],
async unstable_patchRoutesOnMiss({ path, patch, matches }) {
async unstable_patchRoutesOnMiss({ patch }) {
let children = await childrenDfd.promise;
patch(null, children);
},
Expand All @@ -689,6 +689,37 @@ describe("Lazy Route Discovery (Fog of War)", () => {
expect(router.state.matches.map((m) => m.route.id)).toEqual(["test"]);
});

it("does not discover routes during initial SSR hydration when a splat route matches", async () => {
router = createRouter({
history: createMemoryHistory({ initialEntries: ["/test"] }),
routes: [
{
path: "/",
},
{
id: "splat",
loader: () => "SPLAT 2",
path: "*",
},
],
hydrationData: {
loaderData: {
splat: "SPLAT 1",
},
},
async unstable_patchRoutesOnMiss() {
throw new Error("Should not be called");
},
});
router.initialize();

await tick();
expect(router.state.initialized).toBe(true);
expect(router.state.location.pathname).toBe("/test");
expect(router.state.loaderData.splat).toBe("SPLAT 1");
expect(router.state.matches.map((m) => m.route.id)).toEqual(["splat"]);
});

it("discovers new root routes", async () => {
let childrenDfd = createDeferred<AgnosticDataRouteObject[]>();
let childLoaderDfd = createDeferred();
Expand Down
11 changes: 7 additions & 4 deletions packages/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -841,10 +841,13 @@ export function createRouter(init: RouterInit): Router {
initialErrors = { [route.id]: error };
}

// If the user provided a patchRoutesOnMiss implementation and our initial
// match is a splat route, clear them out so we run through lazy discovery
// on hydration in case there's a more accurate lazy route match
if (initialMatches && patchRoutesOnMissImpl) {
// In SPA apps, if the user provided a patchRoutesOnMiss implementation and
// our initial match is a splat route, clear them out so we run through lazy
// discovery on hydration in case there's a more accurate lazy route match.
// In SSR apps (with `hydrationData`), we expect that the server will send
// up the proper matched routes so we don't want to run lazy discovery on
// initial hydration and want to hydrate into the splat route.
if (initialMatches && patchRoutesOnMissImpl && !init.hydrationData) {
let fogOfWar = checkFogOfWar(
initialMatches,
dataRoutes,
Expand Down

0 comments on commit 9e1da44

Please sign in to comment.