Skip to content

Commit daef0f0

Browse files
committed
Reuse static handler matcher for static routers
Assisted-By: devx/597728f0-1b3f-4153-b929-18dbff6cd683
1 parent 61a5758 commit daef0f0

3 files changed

Lines changed: 73 additions & 10 deletions

File tree

packages/react-router/__tests__/dom/data-static-router-test.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,47 @@ beforeEach(() => {
2323
});
2424

2525
describe("A <StaticRouterProvider>", () => {
26+
it("reuses the static handler route matcher", async () => {
27+
let { query } = createStaticHandler([
28+
{
29+
id: "parent",
30+
path: "parent",
31+
children: [
32+
{ id: "child", path: "child" },
33+
{ id: "other", path: "other" },
34+
],
35+
},
36+
]);
37+
let context = (await query(
38+
new Request("http://localhost/parent/child"),
39+
)) as StaticHandlerContext;
40+
expect(typeof context._match).toBe("function");
41+
let otherElement = <h1>Other</h1>;
42+
43+
// This route tree is intentionally invalid so compiling a new matcher for
44+
// it would throw instead of reusing the static handler matcher.
45+
let router = createStaticRouter(
46+
[
47+
{
48+
id: "parent",
49+
path: "parent",
50+
children: [
51+
{ id: "child", path: "/absolute" },
52+
{ id: "other", path: "other", element: otherElement },
53+
],
54+
},
55+
],
56+
context,
57+
);
58+
59+
let matches = router.match("/parent/other");
60+
expect(matches?.map((match) => match.route.id)).toEqual([
61+
"parent",
62+
"other",
63+
]);
64+
expect(matches?.[1].route.element).toBe(otherElement);
65+
});
66+
2667
it("renders an initialized router", async () => {
2768
let hooksData1: {
2869
location: ReturnType<typeof useLocation>;

packages/react-router/lib/dom/server.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,19 +365,20 @@ export function createStaticRouter(
365365
let future: FutureConfig = {
366366
...opts?.future,
367367
};
368-
let dataRouteMatcher = createDataRouteMatcher(context.basename || "/");
369-
dataRouteMatcher.update(dataRoutes);
368+
let matchRoutes = context._match;
369+
let dataRouteMatcher: ReturnType<typeof createDataRouteMatcher> | undefined;
370370

371371
// Because our context matches may be from a set of routes passed to
372372
// createStaticHandler(), we update them here with our newly created/enhanced
373373
// data routes
374-
let matches = context.matches.map((match) => {
374+
let mapRouteMatch = (match: (typeof context.matches)[number]) => {
375375
let route = manifest[match.route.id] || match.route;
376376
return {
377377
...match,
378378
route,
379379
};
380-
});
380+
};
381+
let matches = context.matches.map(mapRouteMatch);
381382

382383
let msg = (method: string) =>
383384
`You cannot use router.${method}() on the server because it is a stateless environment`;
@@ -417,7 +418,18 @@ export function createStaticRouter(
417418
return undefined;
418419
},
419420
match(locationArg) {
420-
return dataRouteMatcher.match(locationArg);
421+
let routeMatches;
422+
if (matchRoutes) {
423+
routeMatches = matchRoutes(locationArg);
424+
} else {
425+
// Contexts not created by createStaticHandler() need their own matcher.
426+
if (!dataRouteMatcher) {
427+
dataRouteMatcher = createDataRouteMatcher(context.basename || "/");
428+
dataRouteMatcher.update(dataRoutes);
429+
}
430+
routeMatches = dataRouteMatcher.match(locationArg);
431+
}
432+
return routeMatches && routeMatches.map(mapRouteMatch);
421433
},
422434
initialize() {
423435
throw msg("initialize");

packages/react-router/lib/router/router.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ export interface StaticHandlerContext {
468468
loaderHeaders: Record<string, Headers>;
469469
actionHeaders: Record<string, Headers>;
470470
_deepestRenderedBoundaryId?: string | null;
471+
/** @private */
472+
_match?: StaticHandler["match"];
471473
}
472474

473475
/**
@@ -4062,6 +4064,8 @@ export function createStaticHandler(
40624064
manifest,
40634065
);
40644066
dataRouteMatcher.update(dataRoutes);
4067+
let match: StaticHandler["match"] = (locationArg) =>
4068+
dataRouteMatcher.match(locationArg);
40654069

40664070
/**
40674071
* The query() method is intended for document requests, in which we want to
@@ -4130,6 +4134,7 @@ export function createStaticHandler(
41304134
statusCode: error.status,
41314135
loaderHeaders: {},
41324136
actionHeaders: {},
4137+
_match: match,
41334138
};
41344139
return generateMiddlewareResponse
41354140
? generateMiddlewareResponse(() => Promise.resolve(staticContext))
@@ -4150,6 +4155,7 @@ export function createStaticHandler(
41504155
statusCode: error.status,
41514156
loaderHeaders: {},
41524157
actionHeaders: {},
4158+
_match: match,
41534159
};
41544160
return generateMiddlewareResponse
41554161
? generateMiddlewareResponse(() => Promise.resolve(staticContext))
@@ -4223,7 +4229,12 @@ export function createStaticHandler(
42234229
// When returning StaticHandlerContext, we patch back in the location here
42244230
// since we need it for React Context. But this helps keep our submit and
42254231
// loadRouteData operating on a Request instead of a Location
4226-
renderedStaticContext = { location, basename, ...result };
4232+
renderedStaticContext = {
4233+
location,
4234+
basename,
4235+
...result,
4236+
_match: match,
4237+
};
42274238
return renderedStaticContext;
42284239
},
42294240
);
@@ -4305,6 +4316,7 @@ export function createStaticHandler(
43054316
statusCode: isRouteErrorResponse(error) ? error.status : 500,
43064317
actionHeaders: {},
43074318
loaderHeaders: {},
4319+
_match: match,
43084320
};
43094321
return generateMiddlewareResponse(() =>
43104322
Promise.resolve(staticContext),
@@ -4342,7 +4354,7 @@ export function createStaticHandler(
43424354
// When returning StaticHandlerContext, we patch back in the location here
43434355
// since we need it for React Context. But this helps keep our submit and
43444356
// loadRouteData operating on a Request instead of a Location
4345-
return { location, basename, ...result };
4357+
return { location, basename, ...result, _match: match };
43464358
}
43474359

43484360
/**
@@ -4963,9 +4975,7 @@ export function createStaticHandler(
49634975

49644976
return {
49654977
dataRoutes,
4966-
match(locationArg) {
4967-
return dataRouteMatcher.match(locationArg);
4968-
},
4978+
match,
49694979
query,
49704980
queryRoute,
49714981
};

0 commit comments

Comments
 (0)