@@ -81,11 +81,7 @@ import {
81
81
DYNAMIC_CSS_MANIFEST ,
82
82
TURBOPACK_CLIENT_MIDDLEWARE_MANIFEST ,
83
83
} from '../shared/lib/constants'
84
- import {
85
- getSortedRoutes ,
86
- isDynamicRoute ,
87
- getSortedRouteObjects ,
88
- } from '../shared/lib/router/utils'
84
+ import { isDynamicRoute } from '../shared/lib/router/utils'
89
85
import type { __ApiPreviewProps } from '../server/api-utils'
90
86
import loadConfig from '../server/config'
91
87
import type { BuildManifest } from '../server/get-page-files'
@@ -210,6 +206,11 @@ import { extractNextErrorCode } from '../lib/error-telemetry-utils'
210
206
import { runAfterProductionCompile } from './after-production-compile'
211
207
import { generatePreviewKeys } from './preview-key-utils'
212
208
import { handleBuildComplete } from './adapter/build-complete'
209
+ import {
210
+ sortPageObjects ,
211
+ sortPages ,
212
+ sortSortableRouteObjects ,
213
+ } from '../shared/lib/router/utils/sortable-routes'
213
214
214
215
type Fallback = null | boolean | string
215
216
@@ -430,7 +431,7 @@ export type RoutesManifest = {
430
431
}
431
432
headers : Array < ManifestHeaderRoute >
432
433
staticRoutes : Array < ManifestRoute >
433
- dynamicRoutes : Array < ManifestRoute >
434
+ dynamicRoutes : ReadonlyArray < ManifestRoute >
434
435
dataRoutes : Array < ManifestDataRoute >
435
436
i18n ?: {
436
437
domains ?: ReadonlyArray < {
@@ -1328,14 +1329,20 @@ export default async function build(
1328
1329
const isAppPPREnabled = checkIsAppPPREnabled ( config . experimental . ppr )
1329
1330
1330
1331
const routesManifestPath = path . join ( distDir , ROUTES_MANIFEST )
1332
+ const dynamicRoutes : Array < ManifestRoute > = [ ]
1333
+
1334
+ /**
1335
+ * A map of all the pages to their sourcePage value. This is only used for
1336
+ * routes that have PPR enabled and clientSegmentEnabled is true.
1337
+ */
1338
+ const sourcePages = new Map < string , string > ( )
1331
1339
const routesManifest : RoutesManifest = nextBuildSpan
1332
1340
. traceChild ( 'generate-routes-manifest' )
1333
1341
. traceFn ( ( ) => {
1334
- const sortedRoutes = getSortedRoutes ( [
1342
+ const sortedRoutes = sortPages ( [
1335
1343
...pageKeys . pages ,
1336
1344
...( pageKeys . app ?? [ ] ) ,
1337
1345
] )
1338
- const dynamicRoutes : Array < ManifestRoute > = [ ]
1339
1346
const staticRoutes : Array < ManifestRoute > = [ ]
1340
1347
1341
1348
for ( const route of sortedRoutes ) {
@@ -2466,7 +2473,7 @@ export default async function build(
2466
2473
if ( serverPropsPages . size > 0 || ssgPages . size > 0 ) {
2467
2474
// We update the routes manifest after the build with the
2468
2475
// data routes since we can't determine these until after build
2469
- routesManifest . dataRoutes = getSortedRoutes ( [
2476
+ routesManifest . dataRoutes = sortPages ( [
2470
2477
...serverPropsPages ,
2471
2478
...ssgPages ,
2472
2479
] ) . map ( ( page ) => {
@@ -2930,39 +2937,39 @@ export default async function build(
2930
2937
// route), any routes that were generated with unknown route params
2931
2938
// should be collected and included in the dynamic routes part
2932
2939
// of the manifest instead.
2933
- const routes : PrerenderedRoute [ ] = [ ]
2934
- const dynamicRoutes : PrerenderedRoute [ ] = [ ]
2940
+ const staticPrerenderedRoutes : PrerenderedRoute [ ] = [ ]
2941
+ const dynamicPrerenderedRoutes : PrerenderedRoute [ ] = [ ]
2935
2942
2936
2943
// Sort the outputted routes to ensure consistent output. Any route
2937
2944
// though that has unknown route params will be pulled and sorted
2938
2945
// independently. This is because the routes with unknown route
2939
2946
// params will contain the dynamic path parameters, some of which
2940
2947
// may conflict with the actual prerendered routes.
2941
- let unknownPrerenderRoutes : PrerenderedRoute [ ] = [ ]
2942
- let knownPrerenderRoutes : PrerenderedRoute [ ] = [ ]
2948
+ const unsortedUnknownPrerenderRoutes : PrerenderedRoute [ ] = [ ]
2949
+ const unsortedKnownPrerenderRoutes : PrerenderedRoute [ ] = [ ]
2943
2950
for ( const prerenderedRoute of prerenderedRoutes ) {
2944
2951
if (
2945
2952
prerenderedRoute . fallbackRouteParams &&
2946
2953
prerenderedRoute . fallbackRouteParams . length > 0
2947
2954
) {
2948
- unknownPrerenderRoutes . push ( prerenderedRoute )
2955
+ unsortedUnknownPrerenderRoutes . push ( prerenderedRoute )
2949
2956
} else {
2950
- knownPrerenderRoutes . push ( prerenderedRoute )
2957
+ unsortedKnownPrerenderRoutes . push ( prerenderedRoute )
2951
2958
}
2952
2959
}
2953
2960
2954
- unknownPrerenderRoutes = getSortedRouteObjects (
2955
- unknownPrerenderRoutes ,
2961
+ const sortedUnknownPrerenderRoutes = sortPageObjects (
2962
+ unsortedUnknownPrerenderRoutes ,
2956
2963
( prerenderedRoute ) => prerenderedRoute . pathname
2957
2964
)
2958
- knownPrerenderRoutes = getSortedRouteObjects (
2959
- knownPrerenderRoutes ,
2965
+ const sortedKnownPrerenderRoutes = sortPageObjects (
2966
+ unsortedKnownPrerenderRoutes ,
2960
2967
( prerenderedRoute ) => prerenderedRoute . pathname
2961
2968
)
2962
2969
2963
2970
prerenderedRoutes = [
2964
- ...knownPrerenderRoutes ,
2965
- ...unknownPrerenderRoutes ,
2971
+ ...sortedKnownPrerenderRoutes ,
2972
+ ...sortedUnknownPrerenderRoutes ,
2966
2973
]
2967
2974
2968
2975
for ( const prerenderedRoute of prerenderedRoutes ) {
@@ -2979,16 +2986,16 @@ export default async function build(
2979
2986
) {
2980
2987
// If the route has unknown params, then we need to add it to
2981
2988
// the list of dynamic routes.
2982
- dynamicRoutes . push ( prerenderedRoute )
2989
+ dynamicPrerenderedRoutes . push ( prerenderedRoute )
2983
2990
} else {
2984
2991
// If the route doesn't have unknown params, then we need to
2985
- // add it to the list of routes.
2986
- routes . push ( prerenderedRoute )
2992
+ // add it to the list of static routes.
2993
+ staticPrerenderedRoutes . push ( prerenderedRoute )
2987
2994
}
2988
2995
}
2989
2996
2990
2997
// Handle all the static routes.
2991
- for ( const route of routes ) {
2998
+ for ( const route of staticPrerenderedRoutes ) {
2992
2999
if ( isDynamicRoute ( page ) && route . pathname === page ) continue
2993
3000
if ( route . pathname === UNDERSCORE_NOT_FOUND_ROUTE ) continue
2994
3001
@@ -3075,7 +3082,7 @@ export default async function build(
3075
3082
// they are enabled, then it'll already be included in the
3076
3083
// prerendered routes.
3077
3084
if ( ! isRoutePPREnabled ) {
3078
- dynamicRoutes . push ( {
3085
+ dynamicPrerenderedRoutes . push ( {
3079
3086
params : { } ,
3080
3087
pathname : page ,
3081
3088
encodedPathname : page ,
@@ -3088,7 +3095,7 @@ export default async function build(
3088
3095
} )
3089
3096
}
3090
3097
3091
- for ( const route of dynamicRoutes ) {
3098
+ for ( const route of dynamicPrerenderedRoutes ) {
3092
3099
const normalizedRoute = normalizePagePath ( route . pathname )
3093
3100
3094
3101
const metadata = exportResult . byPath . get (
@@ -3103,18 +3110,43 @@ export default async function build(
3103
3110
}
3104
3111
3105
3112
let prefetchDataRoute : string | undefined
3113
+ let dynamicRoute = routesManifest . dynamicRoutes . find (
3114
+ ( r ) => r . page === route . pathname
3115
+ )
3106
3116
if ( ! isAppRouteHandler && isAppPPREnabled ) {
3107
3117
prefetchDataRoute = path . posix . join (
3108
3118
`${ normalizedRoute } ${ RSC_PREFETCH_SUFFIX } `
3109
3119
)
3120
+
3121
+ // If the dynamic route wasn't found, then we need to create
3122
+ // it. This ensures that for each fallback shell there's an
3123
+ // entry in the app routes manifest which enables routing for
3124
+ // this fallback shell.
3125
+ if ( ! dynamicRoute ) {
3126
+ dynamicRoute = pageToRoute ( route . pathname )
3127
+ sourcePages . set ( route . pathname , page )
3128
+
3129
+ // This route is not for the internal router, but instead
3130
+ // for external routers.
3131
+ dynamicRoute . skipInternalRouting = true
3132
+
3133
+ // Push this to the end of the array. The dynamic routes are
3134
+ // sorted by page later.
3135
+ dynamicRoutes . push ( dynamicRoute )
3136
+ }
3110
3137
}
3111
3138
3112
3139
if ( ! isAppRouteHandler && metadata ?. segmentPaths ) {
3113
- const dynamicRoute = routesManifest . dynamicRoutes . find (
3114
- ( r ) => r . page === page
3115
- )
3140
+ // If PPR isn't enabled, then we might not find the dynamic
3141
+ // route by pathname. If that's the case, we need to find the
3142
+ // route by page.
3116
3143
if ( ! dynamicRoute ) {
3117
- throw new InvariantError ( 'Dynamic route not found' )
3144
+ dynamicRoute = dynamicRoutes . find ( ( r ) => r . page === page )
3145
+
3146
+ // If it can't be found by page, we must throw an error.
3147
+ if ( ! dynamicRoute ) {
3148
+ throw new InvariantError ( 'Dynamic route not found' )
3149
+ }
3118
3150
}
3119
3151
3120
3152
dynamicRoute . prefetchSegmentDataRoutes ??= [ ]
@@ -3573,11 +3605,16 @@ export default async function build(
3573
3605
}
3574
3606
} )
3575
3607
3576
- // As we may have modified the routesManifest.dynamicRoutes, we need to
3577
- // sort the dynamic routes by page.
3578
- routesManifest . dynamicRoutes = getSortedRouteObjects (
3579
- routesManifest . dynamicRoutes ,
3580
- ( route ) => route . page
3608
+ // As we may have modified the dynamicRoutes, we need to sort the
3609
+ // dynamic routes by page.
3610
+ routesManifest . dynamicRoutes = sortSortableRouteObjects (
3611
+ dynamicRoutes ,
3612
+ ( route ) => ( {
3613
+ // If the route is PPR enabled, and has an associated source page,
3614
+ // use it. Otherwise fallback to the page which should be the same.
3615
+ sourcePage : sourcePages . get ( route . page ) ?? route . page ,
3616
+ page : route . page ,
3617
+ } )
3581
3618
)
3582
3619
3583
3620
// Now write the routes manifest out.
0 commit comments