@@ -4940,32 +4940,41 @@ const lazyRouteFunctionCache = new WeakMap<
49404940 * shouldRevalidate) and update the routeManifest in place which shares objects
49414941 * with dataRoutes so those get updated as well.
49424942 */
4943- async function loadLazyRoute (
4943+ function loadLazyRoute (
49444944 route : AgnosticDataRouteObject ,
49454945 manifest : RouteManifest ,
49464946 mapRouteProperties : MapRoutePropertiesFunction
4947- ) {
4947+ ) : {
4948+ routePromise : Promise < void > | undefined ;
4949+ propertyPromises ?: Partial <
4950+ Record < keyof AgnosticDataRouteObject , Promise < void > >
4951+ > ;
4952+ } {
49484953 let routeToUpdate = manifest [ route . id ] ;
49494954 invariant ( routeToUpdate , "No route found in manifest" ) ;
49504955
49514956 if ( ! route . lazy ) {
4952- return ;
4957+ return { routePromise : undefined } ;
49534958 }
49544959
49554960 if ( typeof route . lazy === "function" ) {
49564961 // Check if we have a cached promise from a previous call
49574962 let cachedPromise = lazyRouteFunctionCache . get ( routeToUpdate ) ;
49584963 if ( cachedPromise ) {
4959- await cachedPromise ;
4960- return ;
4964+ return { routePromise : cachedPromise } ;
49614965 }
49624966
49634967 // We use `.then` to chain additional logic to the lazy route promise so that
49644968 // the consumer's lazy route logic is coupled to our logic for updating the
49654969 // route in place in a single task. This ensures that the cached promise
49664970 // contains all logic for managing the lazy route. This chained promise is
49674971 // then awaited so that consumers of this function see the updated route.
4968- let lazyRoutePromise = route . lazy ( ) . then ( ( lazyRoute ) => {
4972+ let lazyRoutePromise = ( async ( ) => {
4973+ invariant (
4974+ typeof route . lazy === "function" ,
4975+ "No lazy route function found"
4976+ ) ;
4977+ let lazyRoute = await route . lazy ( ) ;
49694978 // Here we update the route in place. This should be safe because there's
49704979 // no way we could yet be sitting on this route as we can't get there
49714980 // without resolving lazy() first.
@@ -5025,26 +5034,32 @@ async function loadLazyRoute(
50255034 ...mapRouteProperties ( routeToUpdate ) ,
50265035 lazy : undefined ,
50275036 } ) ;
5028- } ) ;
5037+ } ) ( ) ;
50295038
50305039 lazyRouteFunctionCache . set ( routeToUpdate , lazyRoutePromise ) ;
5031- await lazyRoutePromise ;
5032-
5033- return ;
5040+ return { routePromise : lazyRoutePromise } ;
50345041 }
50355042
5036- let lazyKeys = Object . keys ( route . lazy ) as Array < keyof typeof route . lazy > ;
5043+ type LazyKey = keyof typeof route . lazy ;
5044+ let lazyKeys = Object . keys ( route . lazy ) as Array < LazyKey > ;
5045+ let propertyPromises : Partial < Record < LazyKey , Promise < void > > > = { } ;
5046+ for ( let key of lazyKeys ) {
5047+ let promise = loadLazyRouteProperty ( {
5048+ key,
5049+ route,
5050+ manifest,
5051+ mapRouteProperties,
5052+ } ) ;
5053+ if ( promise ) {
5054+ propertyPromises [ key ] = promise ;
5055+ }
5056+ }
50375057
5038- await Promise . all (
5039- lazyKeys . map ( ( key ) =>
5040- loadLazyRouteProperty ( {
5041- key,
5042- route,
5043- manifest,
5044- mapRouteProperties,
5045- } )
5046- )
5058+ let routePromise = Promise . all ( Object . values ( propertyPromises ) ) . then (
5059+ ( ) => { }
50475060 ) ;
5061+
5062+ return { routePromise, propertyPromises } ;
50485063}
50495064
50505065function loadLazyMiddlewareForMatches (
@@ -5264,10 +5279,8 @@ async function callDataStrategyImpl(
52645279 manifest ,
52655280 mapRouteProperties
52665281 ) ;
5267- let loadLazyRoutePromises = matches . map ( ( m ) =>
5268- m . route . lazy
5269- ? loadLazyRoute ( m . route , manifest , mapRouteProperties )
5270- : undefined
5282+ let loadLazyRouteResults = matches . map ( ( m ) =>
5283+ loadLazyRoute ( m . route , manifest , mapRouteProperties )
52715284 ) ;
52725285
52735286 // Ensure all middleware is loaded before we start executing routes
@@ -5276,7 +5289,7 @@ async function callDataStrategyImpl(
52765289 }
52775290
52785291 let dsMatches = matches . map ( ( match , i ) => {
5279- let loadRoutePromise = loadLazyRoutePromises [ i ] ;
5292+ let { routePromise , propertyPromises } = loadLazyRouteResults [ i ] ;
52805293 let shouldLoad = matchesToLoad . some ( ( m ) => m . route . id === match . route . id ) ;
52815294 // `resolve` encapsulates route.lazy(), executing the loader/action,
52825295 // and mapping return values/thrown errors to a `DataStrategyResult`. Users
@@ -5290,12 +5303,16 @@ async function callDataStrategyImpl(
52905303 ) {
52915304 shouldLoad = true ;
52925305 }
5306+ let handlerPromise = propertyPromises
5307+ ? propertyPromises [ type ]
5308+ : routePromise ;
52935309 return shouldLoad
52945310 ? callLoaderOrAction (
52955311 type ,
52965312 request ,
52975313 match ,
5298- loadRoutePromise ,
5314+ handlerPromise ,
5315+ routePromise ,
52995316 handlerOverride ,
53005317 scopedContext
53015318 )
@@ -5324,7 +5341,9 @@ async function callDataStrategyImpl(
53245341 // it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` -
53255342 // called from `match.resolve()`
53265343 try {
5327- await Promise . all ( loadLazyRoutePromises ) ;
5344+ await Promise . all (
5345+ loadLazyRouteResults . map ( ( { routePromise } ) => routePromise )
5346+ ) ;
53285347 } catch ( e ) {
53295348 // No-op
53305349 }
@@ -5337,6 +5356,7 @@ async function callLoaderOrAction(
53375356 type : "loader" | "action" ,
53385357 request : Request ,
53395358 match : AgnosticDataRouteMatch ,
5359+ loadHandlerPromise : Promise < void > | undefined ,
53405360 loadRoutePromise : Promise < void > | undefined ,
53415361 handlerOverride : Parameters < DataStrategyMatch [ "resolve" ] > [ 0 ] ,
53425362 scopedContext : unknown
@@ -5394,7 +5414,7 @@ async function callLoaderOrAction(
53945414 | ActionFunction < unknown > ;
53955415
53965416 // If we have a route.lazy promise, await that first
5397- if ( loadRoutePromise ) {
5417+ if ( loadHandlerPromise ) {
53985418 if ( handler ) {
53995419 // Run statically defined handler in parallel with lazy()
54005420 let handlerError ;
@@ -5405,15 +5425,15 @@ async function callLoaderOrAction(
54055425 runHandler ( handler ) . catch ( ( e ) => {
54065426 handlerError = e ;
54075427 } ) ,
5408- loadRoutePromise ,
5428+ loadHandlerPromise ,
54095429 ] ) ;
54105430 if ( handlerError !== undefined ) {
54115431 throw handlerError ;
54125432 }
54135433 result = value ! ;
54145434 } else {
5415- // Load lazy route module , then run any returned handler
5416- await loadRoutePromise ;
5435+ // Load lazy loader/action , then run any returned handler
5436+ await loadHandlerPromise ;
54175437
54185438 handler = match . route [ type ] as
54195439 | LoaderFunction < unknown >
@@ -5422,7 +5442,7 @@ async function callLoaderOrAction(
54225442 // Handler still runs even if we got interrupted to maintain consistency
54235443 // with un-abortable behavior of handler execution on non-lazy or
54245444 // previously-lazy-loaded routes
5425- result = await runHandler ( handler ) ;
5445+ [ result ] = await Promise . all ( [ runHandler ( handler ) , loadRoutePromise ] ) ;
54265446 } else if ( type === "action" ) {
54275447 let url = new URL ( request . url ) ;
54285448 let pathname = url . pathname + url . search ;
0 commit comments