@@ -20,7 +20,10 @@ import {
2020} from '../../../server/route-modules/checks'
2121import { isClientReference } from '../../../lib/client-reference'
2222import { getSegmentParam } from '../../../server/app-render/get-segment-param'
23- import { getLayoutOrPageModule } from '../../../server/lib/app-dir-module'
23+ import {
24+ getLayoutOrPageModule ,
25+ type LoaderTree ,
26+ } from '../../../server/lib/app-dir-module'
2427import { PAGE_SEGMENT_KEY } from '../../../shared/lib/segment'
2528
2629type GenerateStaticParams = ( options : { params ?: Params } ) => Promise < Params [ ] >
@@ -74,17 +77,21 @@ export type AppSegment = {
7477 * @returns the segments for the app page route module
7578 */
7679async function collectAppPageSegments ( routeModule : AppPageRouteModule ) {
77- const segments : AppSegment [ ] = [ ]
80+ // We keep track of unique segments, since with parallel routes, it's possible
81+ // to see the same segment multiple times.
82+ const uniqueSegments = new Map < string , AppSegment > ( )
83+
84+ // Queue will store tuples of [loaderTree, currentSegments]
85+ type QueueItem = [ LoaderTree , AppSegment [ ] ]
86+ const queue : QueueItem [ ] = [ [ routeModule . userland . loaderTree , [ ] ] ]
7887
79- // Helper function to process a loader tree path
80- async function processLoaderTree (
81- loaderTree : any ,
82- currentSegments : AppSegment [ ] = [ ]
83- ) : Promise < void > {
88+ while ( queue . length > 0 ) {
89+ const [ loaderTree , currentSegments ] = queue . shift ( ) !
8490 const [ name , parallelRoutes ] = loaderTree
85- const { mod : userland , filePath } = await getLayoutOrPageModule ( loaderTree )
8691
87- const isClientComponent : boolean = userland && isClientReference ( userland )
92+ // Process current node
93+ const { mod : userland , filePath } = await getLayoutOrPageModule ( loaderTree )
94+ const isClientComponent = userland && isClientReference ( userland )
8895 const isDynamicSegment = / \[ .* \] $ / . test ( name )
8996 const param = isDynamicSegment ? getSegmentParam ( name ) ?. param : undefined
9097
@@ -97,30 +104,40 @@ async function collectAppPageSegments(routeModule: AppPageRouteModule) {
97104 generateStaticParams : undefined ,
98105 }
99106
100- // Only server components can have app segment configurations. If this isn't
101- // an object, then we should skip it. This can happen when parsing the
102- // error components.
107+ // Only server components can have app segment configurations
103108 if ( ! isClientComponent ) {
104109 attach ( segment , userland , routeModule . definition . pathname )
105110 }
106111
107- currentSegments . push ( segment )
112+ // Create a unique key for the segment
113+ const segmentKey = getSegmentKey ( segment )
114+ if ( ! uniqueSegments . has ( segmentKey ) ) {
115+ uniqueSegments . set ( segmentKey , segment )
116+ }
108117
109- // If this is a page segment, we know we've reached a leaf node associated with the
110- // page we're collecting segments for. We can add the collected segments to our final result.
118+ const updatedSegments = [ ...currentSegments , segment ]
119+
120+ // If this is a page segment, we've reached a leaf node
111121 if ( name === PAGE_SEGMENT_KEY ) {
112- segments . push ( ...currentSegments )
122+ // Add all segments in the current path
123+ updatedSegments . forEach ( ( seg ) => {
124+ const key = getSegmentKey ( seg )
125+ uniqueSegments . set ( key , seg )
126+ } )
113127 }
114128
115- // Recursively process parallel routes
129+ // Add all parallel routes to the queue
116130 for ( const parallelRouteKey in parallelRoutes ) {
117131 const parallelRoute = parallelRoutes [ parallelRouteKey ]
118- await processLoaderTree ( parallelRoute , [ ... currentSegments ] )
132+ queue . push ( [ parallelRoute , updatedSegments ] )
119133 }
120134 }
121135
122- await processLoaderTree ( routeModule . userland . loaderTree )
123- return segments
136+ return Array . from ( uniqueSegments . values ( ) )
137+ }
138+
139+ function getSegmentKey ( segment : AppSegment ) {
140+ return `${ segment . name } -${ segment . filePath ?? '' } -${ segment . param ?? '' } `
124141}
125142
126143/**
0 commit comments