Skip to content

Commit 14c7d4e

Browse files
committed
Switch to queryAndRender API
1 parent 0b0efe5 commit 14c7d4e

File tree

2 files changed

+162
-84
lines changed

2 files changed

+162
-84
lines changed

packages/router/__tests__/router-test.ts

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11951,19 +11951,23 @@ describe("a router", () => {
1195111951
});
1195211952

1195311953
it("runs middleware before staticHandler.query", async () => {
11954-
let { query } = createStaticHandler(MIDDLEWARE_ORDERING_ROUTES, {
11955-
future: { unstable_middleware: true },
11956-
});
11954+
let { queryAndRender } = createStaticHandler(
11955+
MIDDLEWARE_ORDERING_ROUTES,
11956+
{
11957+
future: { unstable_middleware: true },
11958+
}
11959+
);
1195711960

11958-
let context = await query(createRequest("/parent/child/grandchild"), {
11959-
render: (context) => {
11961+
let context = await queryAndRender(
11962+
createRequest("/parent/child/grandchild"),
11963+
(context) => {
1196011964
invariant(
1196111965
!(context instanceof Response),
1196211966
"Expected StaticHandlerContext"
1196311967
);
1196411968
return Promise.resolve(json(context.loaderData));
11965-
},
11966-
});
11969+
}
11970+
);
1196711971

1196811972
invariant(
1196911973
context instanceof Response,
@@ -12385,17 +12389,21 @@ describe("a router", () => {
1238512389
});
1238612390

1238712391
it("passes context into staticHandler.query", async () => {
12388-
let { query } = createStaticHandler(MIDDLEWARE_CONTEXT_ROUTES, {
12389-
future: { unstable_middleware: true },
12390-
});
12392+
let { queryAndRender } = createStaticHandler(
12393+
MIDDLEWARE_CONTEXT_ROUTES,
12394+
{
12395+
future: { unstable_middleware: true },
12396+
}
12397+
);
1239112398

12392-
let ctx = await query(createRequest("/parent/child/grandchild"), {
12393-
render: (context) => {
12399+
let ctx = await queryAndRender(
12400+
createRequest("/parent/child/grandchild"),
12401+
(context) => {
1239412402
return Promise.resolve(
1239512403
json((context as StaticHandlerContext).loaderData)
1239612404
);
12397-
},
12398-
});
12405+
}
12406+
);
1239912407

1240012408
invariant(ctx instanceof Response, "Expected Response");
1240112409

@@ -12416,9 +12424,12 @@ describe("a router", () => {
1241612424
});
1241712425

1241812426
it("prefills context in staticHandler.query", async () => {
12419-
let { query } = createStaticHandler(MIDDLEWARE_CONTEXT_ROUTES, {
12420-
future: { unstable_middleware: true },
12421-
});
12427+
let { queryAndRender } = createStaticHandler(
12428+
MIDDLEWARE_CONTEXT_ROUTES,
12429+
{
12430+
future: { unstable_middleware: true },
12431+
}
12432+
);
1242212433

1242312434
let middlewareContext = createMiddlewareStore();
1242412435
let routeMiddlewareContext = getRouteAwareMiddlewareContext(
@@ -12427,14 +12438,15 @@ describe("a router", () => {
1242712438
() => {}
1242812439
);
1242912440
routeMiddlewareContext.set(loaderCountContext, 50);
12430-
let ctx = await query(createRequest("/parent/child/grandchild"), {
12431-
middlewareContext,
12432-
render: (context) => {
12441+
let ctx = await queryAndRender(
12442+
createRequest("/parent/child/grandchild"),
12443+
(context) => {
1243312444
return Promise.resolve(
1243412445
json((context as StaticHandlerContext).loaderData)
1243512446
);
1243612447
},
12437-
});
12448+
{ middlewareContext }
12449+
);
1243812450

1243912451
invariant(ctx instanceof Response, "Expected Response");
1244012452

packages/router/router.ts

Lines changed: 129 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,15 @@ export interface StaticHandlerContext {
356356

357357
interface StaticHandlerQueryOpts {
358358
requestContext?: unknown;
359+
}
360+
361+
interface StaticHandlerQueryAndRenderOpts {
359362
middlewareContext?: InternalMiddlewareContext;
360-
render?: (context: StaticHandlerContext | Response) => Promise<Response>;
361363
}
362364

363-
interface StaticHandlerQueryRouteOpts extends StaticHandlerQueryOpts {
365+
interface StaticHandlerQueryRouteOpts {
366+
requestContext?: unknown;
367+
middlewareContext?: InternalMiddlewareContext;
364368
routeId?: string;
365369
}
366370

@@ -373,6 +377,11 @@ export interface StaticHandler {
373377
request: Request,
374378
opts?: StaticHandlerQueryOpts
375379
): Promise<StaticHandlerContext | Response>;
380+
queryAndRender(
381+
request: Request,
382+
render: (context: StaticHandlerContext | Response) => Promise<Response>,
383+
opts?: StaticHandlerQueryAndRenderOpts
384+
): Promise<Response>;
376385
queryRoute(
377386
request: Request,
378387
opts?: StaticHandlerQueryRouteOpts
@@ -2395,13 +2404,98 @@ export function createStaticHandler(
23952404
*/
23962405
async function query(
23972406
request: Request,
2398-
{ requestContext, middlewareContext, render }: StaticHandlerQueryOpts = {}
2407+
{ requestContext }: StaticHandlerQueryOpts = {}
23992408
): Promise<StaticHandlerContext | Response> {
24002409
invariant(
24012410
request.signal,
24022411
"query() requests must contain an AbortController signal"
24032412
);
2413+
invariant(
2414+
!future.unstable_middleware,
2415+
"staticHandler.query() cannot be used with middleware"
2416+
);
2417+
2418+
let queryInit = initQueryRequest(request);
2419+
2420+
if ("shortCircuitContext" in queryInit) {
2421+
return queryInit.shortCircuitContext;
2422+
}
2423+
2424+
let { location, matches } = queryInit;
2425+
2426+
return runQueryHandlers(
2427+
request,
2428+
location,
2429+
matches,
2430+
requestContext,
2431+
undefined
2432+
);
2433+
}
2434+
2435+
/**
2436+
* The queryAndRender() method is a small extension to query() in which we
2437+
* also accept a render() callback allowing our calling context to transform
2438+
* the staticHandlerContext int oa singular HTML Response we can bubble back
2439+
* up our middleware chain.
2440+
*/
2441+
async function queryAndRender(
2442+
request: Request,
2443+
render: (context: StaticHandlerContext | Response) => Promise<Response>,
2444+
{ middlewareContext }: StaticHandlerQueryAndRenderOpts = {}
2445+
): Promise<Response> {
2446+
invariant(
2447+
request.signal,
2448+
"query() requests must contain an AbortController signal"
2449+
);
2450+
2451+
let queryInit = initQueryRequest(request);
2452+
2453+
if ("shortCircuitContext" in queryInit) {
2454+
return render(queryInit.shortCircuitContext);
2455+
}
2456+
2457+
let { location, matches } = queryInit;
2458+
2459+
if (!future.unstable_middleware) {
2460+
let result = await runQueryHandlers(request, location, matches);
2461+
return render(result);
2462+
}
2463+
2464+
// Since this is a document request, we run middlewares once here for the Request
2465+
// so we don't duplicate middleware executions for parallel loaders
2466+
invariant(
2467+
render != null,
2468+
"Using middleware with staticHandler.query() requires passing a render() function"
2469+
);
2470+
let ctx = middlewareContext || createMiddlewareStore();
2471+
let result = await callRouteSubPipeline(
2472+
request,
2473+
matches,
2474+
0,
2475+
matches[0].params,
2476+
ctx,
2477+
async () => {
2478+
let staticContext = await runQueryHandlers(
2479+
request,
2480+
location,
2481+
matches,
2482+
undefined,
2483+
ctx
2484+
);
2485+
let response = await render(staticContext);
2486+
return response;
2487+
}
2488+
);
2489+
return result;
2490+
}
24042491

2492+
// Initialize an incoming query() or queryAndRender() call, potentially
2493+
// short circuiting if there's nothing to do
2494+
function initQueryRequest(
2495+
request: Request
2496+
):
2497+
| { shortCircuitContext: StaticHandlerContext }
2498+
| { location: Location; matches: AgnosticDataRouteMatch[] } {
24052499
let url = new URL(request.url);
24062500
let method = request.method.toLowerCase();
24072501
let location = createLocation("", createPath(url), null, "default");
@@ -2413,78 +2507,49 @@ export function createStaticHandler(
24132507
let { matches: methodNotAllowedMatches, route } =
24142508
getShortCircuitMatches(dataRoutes);
24152509
return {
2416-
basename,
2417-
location,
2418-
matches: methodNotAllowedMatches,
2419-
loaderData: {},
2420-
actionData: null,
2421-
errors: {
2422-
[route.id]: error,
2510+
shortCircuitContext: {
2511+
basename,
2512+
location,
2513+
matches: methodNotAllowedMatches,
2514+
loaderData: {},
2515+
actionData: null,
2516+
errors: {
2517+
[route.id]: error,
2518+
},
2519+
statusCode: error.status,
2520+
loaderHeaders: {},
2521+
actionHeaders: {},
2522+
activeDeferreds: null,
24232523
},
2424-
statusCode: error.status,
2425-
loaderHeaders: {},
2426-
actionHeaders: {},
2427-
activeDeferreds: null,
24282524
};
2429-
} else if (!matches) {
2525+
}
2526+
2527+
if (!matches) {
24302528
let error = getInternalRouterError(404, { pathname: location.pathname });
24312529
let { matches: notFoundMatches, route } =
24322530
getShortCircuitMatches(dataRoutes);
24332531
return {
2434-
basename,
2435-
location,
2436-
matches: notFoundMatches,
2437-
loaderData: {},
2438-
actionData: null,
2439-
errors: {
2440-
[route.id]: error,
2532+
shortCircuitContext: {
2533+
basename,
2534+
location,
2535+
matches: notFoundMatches,
2536+
loaderData: {},
2537+
actionData: null,
2538+
errors: {
2539+
[route.id]: error,
2540+
},
2541+
statusCode: error.status,
2542+
loaderHeaders: {},
2543+
actionHeaders: {},
2544+
activeDeferreds: null,
24412545
},
2442-
statusCode: error.status,
2443-
loaderHeaders: {},
2444-
actionHeaders: {},
2445-
activeDeferreds: null,
24462546
};
24472547
}
24482548

2449-
// Since this is a document request, we run middlewares once here for the Request
2450-
// so we don't duplicate middleware executions for parallel loaders
2451-
if (future.unstable_middleware) {
2452-
invariant(
2453-
render != null,
2454-
"Using middleware with staticHandler.query() requires passing a render() function"
2455-
);
2456-
let ctx = middlewareContext || createMiddlewareStore();
2457-
let result = await callRouteSubPipeline(
2458-
request,
2459-
matches,
2460-
0,
2461-
matches[0].params,
2462-
ctx,
2463-
async () => {
2464-
let staticContext = await runQueryHandlers(
2465-
request,
2466-
location,
2467-
matches!,
2468-
undefined,
2469-
ctx
2470-
);
2471-
let response = await render(staticContext);
2472-
return response;
2473-
}
2474-
);
2475-
return result;
2476-
} else {
2477-
let result = runQueryHandlers(
2478-
request,
2479-
location,
2480-
matches!,
2481-
requestContext,
2482-
undefined
2483-
);
2484-
return result;
2485-
}
2549+
return { location, matches };
24862550
}
24872551

2552+
// Run the appropriate handlers for a query() or queryAndRender() call
24882553
async function runQueryHandlers(
24892554
request: Request,
24902555
location: Location,
@@ -2973,6 +3038,7 @@ export function createStaticHandler(
29733038
return {
29743039
dataRoutes,
29753040
query,
3041+
queryAndRender,
29763042
queryRoute,
29773043
};
29783044
}

0 commit comments

Comments
 (0)