@@ -356,11 +356,15 @@ export interface StaticHandlerContext {
356
356
357
357
interface StaticHandlerQueryOpts {
358
358
requestContext ?: unknown ;
359
+ }
360
+
361
+ interface StaticHandlerQueryAndRenderOpts {
359
362
middlewareContext ?: InternalMiddlewareContext ;
360
- render ?: ( context : StaticHandlerContext | Response ) => Promise < Response > ;
361
363
}
362
364
363
- interface StaticHandlerQueryRouteOpts extends StaticHandlerQueryOpts {
365
+ interface StaticHandlerQueryRouteOpts {
366
+ requestContext ?: unknown ;
367
+ middlewareContext ?: InternalMiddlewareContext ;
364
368
routeId ?: string ;
365
369
}
366
370
@@ -373,6 +377,11 @@ export interface StaticHandler {
373
377
request : Request ,
374
378
opts ?: StaticHandlerQueryOpts
375
379
) : Promise < StaticHandlerContext | Response > ;
380
+ queryAndRender (
381
+ request : Request ,
382
+ render : ( context : StaticHandlerContext | Response ) => Promise < Response > ,
383
+ opts ?: StaticHandlerQueryAndRenderOpts
384
+ ) : Promise < Response > ;
376
385
queryRoute (
377
386
request : Request ,
378
387
opts ?: StaticHandlerQueryRouteOpts
@@ -2395,13 +2404,98 @@ export function createStaticHandler(
2395
2404
*/
2396
2405
async function query (
2397
2406
request : Request ,
2398
- { requestContext, middlewareContext , render } : StaticHandlerQueryOpts = { }
2407
+ { requestContext } : StaticHandlerQueryOpts = { }
2399
2408
) : Promise < StaticHandlerContext | Response > {
2400
2409
invariant (
2401
2410
request . signal ,
2402
2411
"query() requests must contain an AbortController signal"
2403
2412
) ;
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
+ }
2404
2491
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 [ ] } {
2405
2499
let url = new URL ( request . url ) ;
2406
2500
let method = request . method . toLowerCase ( ) ;
2407
2501
let location = createLocation ( "" , createPath ( url ) , null , "default" ) ;
@@ -2413,78 +2507,49 @@ export function createStaticHandler(
2413
2507
let { matches : methodNotAllowedMatches , route } =
2414
2508
getShortCircuitMatches ( dataRoutes ) ;
2415
2509
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 ,
2423
2523
} ,
2424
- statusCode : error . status ,
2425
- loaderHeaders : { } ,
2426
- actionHeaders : { } ,
2427
- activeDeferreds : null ,
2428
2524
} ;
2429
- } else if ( ! matches ) {
2525
+ }
2526
+
2527
+ if ( ! matches ) {
2430
2528
let error = getInternalRouterError ( 404 , { pathname : location . pathname } ) ;
2431
2529
let { matches : notFoundMatches , route } =
2432
2530
getShortCircuitMatches ( dataRoutes ) ;
2433
2531
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 ,
2441
2545
} ,
2442
- statusCode : error . status ,
2443
- loaderHeaders : { } ,
2444
- actionHeaders : { } ,
2445
- activeDeferreds : null ,
2446
2546
} ;
2447
2547
}
2448
2548
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 } ;
2486
2550
}
2487
2551
2552
+ // Run the appropriate handlers for a query() or queryAndRender() call
2488
2553
async function runQueryHandlers (
2489
2554
request : Request ,
2490
2555
location : Location ,
@@ -2973,6 +3038,7 @@ export function createStaticHandler(
2973
3038
return {
2974
3039
dataRoutes,
2975
3040
query,
3041
+ queryAndRender,
2976
3042
queryRoute,
2977
3043
} ;
2978
3044
}
0 commit comments