@@ -249,7 +249,8 @@ export interface Router {
249
249
* PRIVATE DO NOT USE
250
250
*
251
251
* Patch additional children routes into an existing parent route
252
- * @param routeId The parent route id
252
+ * @param routeId The parent route id or a callback function accepting `patch`
253
+ * to perform batch patching
253
254
* @param children The additional children routes
254
255
*/
255
256
patchRoutes ( routeId : string | null , children : AgnosticRouteObject [ ] ) : void ;
@@ -1222,6 +1223,7 @@ export function createRouter(init: RouterInit): Router {
1222
1223
isMutationMethod ( state . navigation . formMethod ) &&
1223
1224
location . state ?. _isRedirect !== true ) ;
1224
1225
1226
+ // Commit any in-flight routes at the end of the HMR revalidation "navigation"
1225
1227
if ( inFlightDataRoutes ) {
1226
1228
dataRoutes = inFlightDataRoutes ;
1227
1229
inFlightDataRoutes = undefined ;
@@ -3204,26 +3206,37 @@ export function createRouter(init: RouterInit): Router {
3204
3206
? partialMatches [ partialMatches . length - 1 ] . route
3205
3207
: null ;
3206
3208
while ( true ) {
3209
+ let isNonHMR = inFlightDataRoutes == null ;
3210
+ let routesToUse = inFlightDataRoutes || dataRoutes ;
3207
3211
try {
3208
3212
await loadLazyRouteChildren (
3209
3213
patchRoutesOnMissImpl ! ,
3210
3214
pathname ,
3211
3215
partialMatches ,
3212
- dataRoutes || inFlightDataRoutes ,
3216
+ routesToUse ,
3213
3217
manifest ,
3214
3218
mapRouteProperties ,
3215
3219
pendingPatchRoutes ,
3216
3220
signal
3217
3221
) ;
3218
3222
} catch ( e ) {
3219
3223
return { type : "error" , error : e , partialMatches } ;
3224
+ } finally {
3225
+ // If we are not in the middle of an HMR revalidation and we changed the
3226
+ // routes, provide a new identity so when we `updateState` at the end of
3227
+ // this navigation/fetch `router.routes` will be a new identity and
3228
+ // trigger a re-run of memoized `router.routes` dependencies.
3229
+ // HMR will already update the identity and reflow when it lands
3230
+ // `inFlightDataRoutes` in `completeNavigation`
3231
+ if ( isNonHMR ) {
3232
+ dataRoutes = [ ...dataRoutes ] ;
3233
+ }
3220
3234
}
3221
3235
3222
3236
if ( signal . aborted ) {
3223
3237
return { type : "aborted" } ;
3224
3238
}
3225
3239
3226
- let routesToUse = inFlightDataRoutes || dataRoutes ;
3227
3240
let newMatches = matchRoutes ( routesToUse , pathname , basename ) ;
3228
3241
let matchedSplat = false ;
3229
3242
if ( newMatches ) {
@@ -3284,6 +3297,31 @@ export function createRouter(init: RouterInit): Router {
3284
3297
) ;
3285
3298
}
3286
3299
3300
+ function patchRoutes (
3301
+ routeId : string | null ,
3302
+ children : AgnosticRouteObject [ ]
3303
+ ) : void {
3304
+ let isNonHMR = inFlightDataRoutes == null ;
3305
+ let routesToUse = inFlightDataRoutes || dataRoutes ;
3306
+ patchRoutesImpl (
3307
+ routeId ,
3308
+ children ,
3309
+ routesToUse ,
3310
+ manifest ,
3311
+ mapRouteProperties
3312
+ ) ;
3313
+
3314
+ // If we are not in the middle of an HMR revalidation and we changed the
3315
+ // routes, provide a new identity and trigger a reflow via `updateState`
3316
+ // to re-run memoized `router.routes` dependencies.
3317
+ // HMR will already update the identity and reflow when it lands
3318
+ // `inFlightDataRoutes` in `completeNavigation`
3319
+ if ( isNonHMR ) {
3320
+ dataRoutes = [ ...dataRoutes ] ;
3321
+ updateState ( { } ) ;
3322
+ }
3323
+ }
3324
+
3287
3325
router = {
3288
3326
get basename ( ) {
3289
3327
return basename ;
@@ -3315,15 +3353,7 @@ export function createRouter(init: RouterInit): Router {
3315
3353
dispose,
3316
3354
getBlocker,
3317
3355
deleteBlocker,
3318
- patchRoutes ( routeId , children ) {
3319
- return patchRoutes (
3320
- routeId ,
3321
- children ,
3322
- dataRoutes || inFlightDataRoutes ,
3323
- manifest ,
3324
- mapRouteProperties
3325
- ) ;
3326
- } ,
3356
+ patchRoutes,
3327
3357
_internalFetchControllers : fetchControllers ,
3328
3358
_internalActiveDeferreds : activeDeferreds ,
3329
3359
// TODO: Remove setRoutes, it's temporary to avoid dealing with
@@ -4488,7 +4518,7 @@ function shouldRevalidateLoader(
4488
4518
}
4489
4519
4490
4520
/**
4491
- * Idempotent utility to execute route.children() method to lazily load route
4521
+ * Idempotent utility to execute patchRoutesOnMiss() to lazily load route
4492
4522
* definitions and update the routes/routeManifest
4493
4523
*/
4494
4524
async function loadLazyRouteChildren (
@@ -4510,7 +4540,7 @@ async function loadLazyRouteChildren(
4510
4540
matches,
4511
4541
patch : ( routeId , children ) => {
4512
4542
if ( ! signal . aborted ) {
4513
- patchRoutes (
4543
+ patchRoutesImpl (
4514
4544
routeId ,
4515
4545
children ,
4516
4546
routes ,
@@ -4531,10 +4561,10 @@ async function loadLazyRouteChildren(
4531
4561
}
4532
4562
}
4533
4563
4534
- function patchRoutes (
4564
+ function patchRoutesImpl (
4535
4565
routeId : string | null ,
4536
4566
children : AgnosticRouteObject [ ] ,
4537
- routes : AgnosticDataRouteObject [ ] ,
4567
+ routesToUse : AgnosticDataRouteObject [ ] ,
4538
4568
manifest : RouteManifest ,
4539
4569
mapRouteProperties : MapRoutePropertiesFunction
4540
4570
) {
@@ -4559,10 +4589,10 @@ function patchRoutes(
4559
4589
let dataChildren = convertRoutesToDataRoutes (
4560
4590
children ,
4561
4591
mapRouteProperties ,
4562
- [ "patch" , String ( routes . length || "0" ) ] ,
4592
+ [ "patch" , String ( routesToUse . length || "0" ) ] ,
4563
4593
manifest
4564
4594
) ;
4565
- routes . push ( ...dataChildren ) ;
4595
+ routesToUse . push ( ...dataChildren ) ;
4566
4596
}
4567
4597
}
4568
4598
0 commit comments