Skip to content

Commit 39400b6

Browse files
committed
fix(build): enable prerendering of interception routes with generateStaticParams
Fixes a bug where interception routes in parallel slots could not be prerendered using generateStaticParams. The previous implementation only examined "children" segments when building static paths, missing segments from parallel routes that contribute to the pathname. Introduces extractPathnameSegments() which: - Traverses the entire loader tree (children + parallel routes) using BFS - Correctly tracks URL depth (skipping route groups/parallel markers, including interception markers which are actual URL components) - Validates that static segment prefixes match the target pathname - Returns ALL segments that contribute to pathname construction This enables routes like app/@modal/(.)photo/[id] to be prerendered when they export generateStaticParams, fixing 404 responses that occurred when these routes were accessed directly.
1 parent 482ed70 commit 39400b6

File tree

14 files changed

+3146
-1690
lines changed

14 files changed

+3146
-1690
lines changed

packages/next/errors.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,5 +924,7 @@
924924
"923": "%s is being parsed as a normalized route, but it has a route group or parallel route segment.",
925925
"924": "Invalid interception route: %s",
926926
"925": "You cannot define a route with the same specificity as an optional catch-all route (\"%s\" and \"/[[...%s]]\").",
927-
"926": "Optional route parameters are not yet supported (\"[%s]\") in route \"%s\"."
927+
"926": "Optional route parameters are not yet supported (\"[%s]\") in route \"%s\".",
928+
"927": "Expected a dynamic route, but got a static route: %s",
929+
"928": "Unexpected empty path segments match for a route \"%s\" with param \"%s\" of type \"%s\""
928930
}

packages/next/src/build/segment-config/app/app-segments.ts

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ import {
1212
isAppPageRouteModule,
1313
} from '../../../server/route-modules/checks'
1414
import { isClientReference } from '../../../lib/client-and-server-references'
15-
import { getSegmentParam } from '../../../shared/lib/router/utils/get-segment-param'
15+
import {
16+
getSegmentParam,
17+
type SegmentParam,
18+
} from '../../../shared/lib/router/utils/get-segment-param'
1619
import {
1720
getLayoutOrPageModule,
1821
type LoaderTree,
1922
} from '../../../server/lib/app-dir-module'
2023
import { PAGE_SEGMENT_KEY } from '../../../shared/lib/segment'
21-
import type { FallbackRouteParam } from '../../static-paths/types'
22-
import { createFallbackRouteParam } from '../../static-paths/utils'
2324
import type { DynamicParamTypes } from '../../../shared/lib/app-router-types'
2425

2526
type GenerateStaticParams = (options: { params?: Params }) => Promise<Params[]>
@@ -223,17 +224,17 @@ export function collectSegments(
223224
}
224225

225226
/**
226-
* Collects the fallback route params for a given app page route module. This is
227-
* a variant of the `collectSegments` function that only collects the fallback
228-
* route params without importing anything.
227+
* Collects the segment params for a given app page route module. This is
228+
* a variant of the `collectSegments` function that only collects the segment
229+
* params without importing anything.
229230
*
230231
* @param routeModule the app page route module
231-
* @returns the fallback route params for the app page route module
232+
* @returns the segment params for the app page route module
232233
*/
233-
export function collectFallbackRouteParams(
234+
export function collectSegmentParams(
234235
routeModule: AppPageRouteModule
235-
): readonly FallbackRouteParam[] {
236-
const uniqueSegments = new Map<string, FallbackRouteParam>()
236+
): readonly SegmentParam[] {
237+
const uniqueSegments = new Map<string, SegmentParam>()
237238

238239
// Queue will store tuples of [loaderTree, isParallelRouteSegment]
239240
type QueueItem = [loaderTree: LoaderTree, isParallelRouteSegment: boolean]
@@ -248,14 +249,7 @@ export function collectFallbackRouteParams(
248249
if (segmentParam) {
249250
const key = `${name}-${segmentParam.param}-${isParallelRouteSegment ? 'pr' : 'np'}`
250251
if (!uniqueSegments.has(key)) {
251-
uniqueSegments.set(
252-
key,
253-
createFallbackRouteParam(
254-
segmentParam.param,
255-
segmentParam.type,
256-
isParallelRouteSegment
257-
)
258-
)
252+
uniqueSegments.set(key, segmentParam)
259253
}
260254
}
261255

0 commit comments

Comments
 (0)