@@ -18,9 +18,8 @@ import {
18
18
import { createRequestInit } from "./data" ;
19
19
import type { AssetsManifest , EntryContext } from "./entry" ;
20
20
import { escapeHtml } from "./markup" ;
21
- import type { RouteModule , RouteModules } from "./routeModules" ;
21
+ import type { RouteModules } from "./routeModules" ;
22
22
import invariant from "./invariant" ;
23
- import type { EntryRoute } from "./routes" ;
24
23
25
24
export const SingleFetchRedirectSymbol = Symbol ( "SingleFetchRedirect" ) ;
26
25
@@ -316,22 +315,16 @@ async function singleFetchLoaderNavigationStrategy(
316
315
matches : DataStrategyFunctionArgs [ "matches" ] ,
317
316
basename : string | undefined
318
317
) {
319
- // Track which routes need a server load - in case we need to tack on a
320
- // `_routes` param
318
+ // Track which routes need a server load for use in a `_routes` param
321
319
let routesParams = new Set < string > ( ) ;
322
320
323
- // We only add `_routes` when one or more routes opts out of a load via
324
- // `shouldRevalidate` or `clientLoader`
321
+ // Only add `_routes` when at least 1 route opts out via `shouldRevalidate`/`clientLoader`
325
322
let foundOptOutRoute = false ;
326
323
327
- // Deferreds for each route so we can be sure they've all loaded via
328
- // `match.resolve()`, and a singular promise that can tell us all routes
329
- // have been resolved
324
+ // Deferreds per-route so we can be sure they've all loaded via `match.resolve()`
330
325
let routeDfds = matches . map ( ( ) => createDeferred < void > ( ) ) ;
331
- let routesLoadedPromise = Promise . all ( routeDfds . map ( ( d ) => d . promise ) ) ;
332
326
333
- // Deferred that we'll use for the call to the server that each match can
334
- // await and parse out it's specific result
327
+ // Deferred we'll use for the singleular call to the server
335
328
let singleFetchDfd = createDeferred < SingleFetchResults > ( ) ;
336
329
337
330
// Base URL and RequestInit for calls to the server
@@ -347,10 +340,8 @@ async function singleFetchLoaderNavigationStrategy(
347
340
routeDfds [ i ] . resolve ( ) ;
348
341
349
342
let manifestRoute = manifest . routes [ m . route . id ] ;
343
+ invariant ( manifestRoute , "No manifest route found for dataStrategy" ) ;
350
344
351
- // Note: If this logic changes for routes that should not participate
352
- // in Single Fetch, make sure you update getLowestLoadingIndex above
353
- // as well
354
345
if ( ! m . shouldLoad ) {
355
346
// If we're not yet initialized and this is the initial load, respect
356
347
// `shouldLoad` because we're only dealing with `clientLoader.hydrate`
@@ -364,7 +355,6 @@ async function singleFetchLoaderNavigationStrategy(
364
355
// via `shouldRevalidate`
365
356
if (
366
357
m . route . id in router . state . loaderData &&
367
- manifestRoute &&
368
358
m . route . shouldRevalidate
369
359
) {
370
360
if ( manifestRoute . hasLoader ) {
@@ -378,7 +368,7 @@ async function singleFetchLoaderNavigationStrategy(
378
368
379
369
// When a route has a client loader, it opts out of the singular call and
380
370
// calls it's server loader via `serverLoader()` using a `?_routes` param
381
- if ( manifestRoute && manifestRoute . hasClientLoader ) {
371
+ if ( manifestRoute . hasClientLoader ) {
382
372
if ( manifestRoute . hasLoader ) {
383
373
foundOptOutRoute = true ;
384
374
}
@@ -422,7 +412,7 @@ async function singleFetchLoaderNavigationStrategy(
422
412
) ;
423
413
424
414
// Wait for all routes to resolve above before we make the HTTP call
425
- await routesLoadedPromise ;
415
+ await Promise . all ( routeDfds . map ( ( d ) => d . promise ) ) ;
426
416
427
417
// We can skip the server call:
428
418
// - On initial hydration - only clientLoaders can pass through via `clientLoader.hydrate`
@@ -437,24 +427,18 @@ async function singleFetchLoaderNavigationStrategy(
437
427
) {
438
428
singleFetchDfd . resolve ( { } ) ;
439
429
} else {
440
- try {
441
- // When one or more routes have opted out, we add a _routes param to
442
- // limit the loaders to those that have a server loader and did not
443
- // opt out
444
- if ( ssr && foundOptOutRoute && routesParams . size > 0 ) {
445
- url . searchParams . set (
446
- "_routes" ,
447
- matches
448
- . filter ( ( m ) => routesParams . has ( m . route . id ) )
449
- . map ( ( m ) => m . route . id )
450
- . join ( "," )
451
- ) ;
452
- }
430
+ // When routes have opted out, add a `_routes` param to filter server loaders
431
+ // Skipped in `ssr:false` because we expect to be loading static `.data` files
432
+ if ( ssr && foundOptOutRoute && routesParams . size > 0 ) {
433
+ let routes = [ ...routesParams . keys ( ) ] . join ( "," ) ;
434
+ url . searchParams . set ( "_routes" , routes ) ;
435
+ }
453
436
437
+ try {
454
438
let data = await fetchAndDecode ( url , init ) ;
455
439
singleFetchDfd . resolve ( data . data as SingleFetchResults ) ;
456
440
} catch ( e ) {
457
- singleFetchDfd . reject ( e as Error ) ;
441
+ singleFetchDfd . reject ( e ) ;
458
442
}
459
443
}
460
444
@@ -673,17 +657,18 @@ function unwrapSingleFetchResult(result: SingleFetchResult, routeId: string) {
673
657
}
674
658
}
675
659
660
+ type Deferred = ReturnType < typeof createDeferred > ;
676
661
function createDeferred < T = unknown > ( ) {
677
662
let resolve : ( val ?: any ) => Promise < void > ;
678
- let reject : ( error ?: Error ) => Promise < void > ;
663
+ let reject : ( error ?: unknown ) => Promise < void > ;
679
664
let promise = new Promise < T > ( ( res , rej ) => {
680
665
resolve = async ( val : T ) => {
681
666
res ( val ) ;
682
667
try {
683
668
await promise ;
684
669
} catch ( e ) { }
685
670
} ;
686
- reject = async ( error ?: Error ) => {
671
+ reject = async ( error ?: unknown ) => {
687
672
rej ( error ) ;
688
673
try {
689
674
await promise ;
0 commit comments