Skip to content

Commit e9e85e8

Browse files
committed
feat(app-router): enable type-aware parameter tracking and resolve parallel route param inconsistencies
Removes special-case filtering for parallel route parameters that caused inconsistent behavior and adds explicit parameter type tracking throughout the routing system. This enables more predictable parameter resolution and provides foundation for advanced parameter handling features. Key improvements: - Add DynamicParamTypes to track parameter semantics - Introduce resolveParallelRouteParams for consistent param handling - Remove parallel route exclusion logic from build pipeline - Enhance FallbackRouteParam with type information
1 parent 3d9dc30 commit e9e85e8

File tree

22 files changed

+1756
-318
lines changed

22 files changed

+1756
-318
lines changed

packages/next/errors.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,6 @@
782782
"781": "No LRU node to remove",
783783
"782": "Failed to find the root directory of the project. This is a bug in Next.js.",
784784
"783": "\\`experimental.clientParamParsing\\` can not be \\`true\\` when \\`experimental.clientSegmentCache\\` is \\`false\\`. Client param parsing is only relevant when client segment cache is enabled.",
785-
"784": "Unexpected dynamic param type: %s",
786-
"785": "Expected RSC response, got %s",
787-
"786": "Invariant: Expected RSC response, got %s"
785+
"784": "Expected RSC response, got %s",
786+
"785": "Unexpected dynamic param type: %s"
788787
}

packages/next/src/build/index.ts

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3134,12 +3134,7 @@ export default async function build(
31343134
for (const prerenderedRoute of prerenderedRoutes) {
31353135
if (
31363136
prerenderedRoute.fallbackRouteParams &&
3137-
prerenderedRoute.fallbackRouteParams.length > 0 &&
3138-
// If all the fallback route params are parallel route params,
3139-
// then we still consider it a known route.
3140-
!prerenderedRoute.fallbackRouteParams.every(
3141-
(param) => param.isParallelRouteParam
3142-
)
3137+
prerenderedRoute.fallbackRouteParams.length > 0
31433138
) {
31443139
unsortedUnknownPrerenderRoutes.push(prerenderedRoute)
31453140
} else {
@@ -3165,12 +3160,7 @@ export default async function build(
31653160
if (
31663161
isRoutePPREnabled &&
31673162
prerenderedRoute.fallbackRouteParams &&
3168-
prerenderedRoute.fallbackRouteParams.length > 0 &&
3169-
// If all the fallback route params are parallel route params,
3170-
// then we still consider it a static route.
3171-
!prerenderedRoute.fallbackRouteParams.every(
3172-
(param) => param.isParallelRouteParam
3173-
)
3163+
prerenderedRoute.fallbackRouteParams.length > 0
31743164
) {
31753165
// If the route has unknown params, then we need to add it to
31763166
// the list of dynamic routes.
@@ -3478,14 +3468,7 @@ export default async function build(
34783468
: undefined,
34793469
fallbackSourceRoute:
34803470
route.fallbackRouteParams &&
3481-
route.fallbackRouteParams.length > 0 &&
3482-
// If all the fallback route params are parallel route
3483-
// params, then we still consider it a static route. This is
3484-
// required to ensure that the changes are backwards
3485-
// compatible with the previous builder implementations.
3486-
!route.fallbackRouteParams.every(
3487-
(param) => param.isParallelRouteParam
3488-
)
3471+
route.fallbackRouteParams.length > 0
34893472
? page
34903473
: undefined,
34913474
fallbackRouteParams: route.fallbackRouteParams,

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import { PAGE_SEGMENT_KEY } from '../../../shared/lib/segment'
2121
import type { FallbackRouteParam } from '../../static-paths/types'
2222
import { createFallbackRouteParam } from '../../static-paths/utils'
23+
import type { DynamicParamTypes } from '../../../shared/lib/app-router-types'
2324

2425
type GenerateStaticParams = (options: { params?: Params }) => Promise<Params[]>
2526

@@ -59,6 +60,7 @@ function attach(segment: AppSegment, userland: unknown, route: string) {
5960
export type AppSegment = {
6061
name: string
6162
paramName: string | undefined
63+
paramType: DynamicParamTypes | undefined
6264
filePath: string | undefined
6365
config: AppSegmentConfig | undefined
6466
isDynamicSegment: boolean
@@ -98,11 +100,12 @@ async function collectAppPageSegments(routeModule: AppPageRouteModule) {
98100
const { mod: userland, filePath } = await getLayoutOrPageModule(loaderTree)
99101
const isClientComponent = userland && isClientReference(userland)
100102

101-
const paramName = getSegmentParam(name)?.param
103+
const { param: paramName, type: paramType } = getSegmentParam(name) ?? {}
102104

103105
const segment: AppSegment = {
104106
name,
105107
paramName,
108+
paramType,
106109
filePath,
107110
config: undefined,
108111
isDynamicSegment: !!paramName,
@@ -169,11 +172,12 @@ function collectAppRouteSegments(
169172

170173
// Generate all the segments.
171174
const segments: AppSegment[] = parts.map((name) => {
172-
const paramName = getSegmentParam(name)?.param
175+
const { param: paramName, type: paramType } = getSegmentParam(name) ?? {}
173176

174177
return {
175178
name,
176179
paramName,
180+
paramType,
177181
filePath: undefined,
178182
isDynamicSegment: !!paramName,
179183
config: undefined,
@@ -244,7 +248,11 @@ export function collectFallbackRouteParams(
244248
if (!uniqueSegments.has(key)) {
245249
uniqueSegments.set(
246250
key,
247-
createFallbackRouteParam(segmentParam.param, isParallelRouteSegment)
251+
createFallbackRouteParam(
252+
segmentParam.param,
253+
segmentParam.type,
254+
isParallelRouteSegment
255+
)
248256
)
249257
}
250258
}

0 commit comments

Comments
 (0)