@@ -20,7 +20,10 @@ import {
20
20
} from '../../../server/route-modules/checks'
21
21
import { isClientReference } from '../../../lib/client-reference'
22
22
import { 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'
24
27
import { PAGE_SEGMENT_KEY } from '../../../shared/lib/segment'
25
28
26
29
type GenerateStaticParams = ( options : { params ?: Params } ) => Promise < Params [ ] >
@@ -74,17 +77,21 @@ export type AppSegment = {
74
77
* @returns the segments for the app page route module
75
78
*/
76
79
async 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 , [ ] ] ]
78
87
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 ( ) !
84
90
const [ name , parallelRoutes ] = loaderTree
85
- const { mod : userland , filePath } = await getLayoutOrPageModule ( loaderTree )
86
91
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 )
88
95
const isDynamicSegment = / \[ .* \] $ / . test ( name )
89
96
const param = isDynamicSegment ? getSegmentParam ( name ) ?. param : undefined
90
97
@@ -97,30 +104,40 @@ async function collectAppPageSegments(routeModule: AppPageRouteModule) {
97
104
generateStaticParams : undefined ,
98
105
}
99
106
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
103
108
if ( ! isClientComponent ) {
104
109
attach ( segment , userland , routeModule . definition . pathname )
105
110
}
106
111
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
+ }
108
117
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
111
121
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
+ } )
113
127
}
114
128
115
- // Recursively process parallel routes
129
+ // Add all parallel routes to the queue
116
130
for ( const parallelRouteKey in parallelRoutes ) {
117
131
const parallelRoute = parallelRoutes [ parallelRouteKey ]
118
- await processLoaderTree ( parallelRoute , [ ... currentSegments ] )
132
+ queue . push ( [ parallelRoute , updatedSegments ] )
119
133
}
120
134
}
121
135
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 ?? '' } `
124
141
}
125
142
126
143
/**
0 commit comments