@@ -69,6 +69,9 @@ const buildPagesCacheValue = async (
6969 revalidate : initialRevalidateSeconds ,
7070} )
7171
72+ const RSC_SEGMENTS_DIR_SUFFIX = '.segments'
73+ const RSC_SEGMENT_SUFFIX = '.segment.rsc'
74+
7275const buildAppCacheValue = async (
7376 path : string ,
7477 shouldUseAppPageKind : boolean ,
@@ -78,6 +81,29 @@ const buildAppCacheValue = async (
7881
7982 // supporting both old and new cache kind for App Router pages - https://github.com/vercel/next.js/pull/65988
8083 if ( shouldUseAppPageKind ) {
84+ // segments are normalized and outputted separately for each segment, we denormalize it here and stitch
85+ // fully constructed segmentData to avoid data fetch waterfalls later in cache handler at runtime
86+ // https://github.com/vercel/next.js/blob/def2c6ba75dff754767379afb44c26c30bd3d96b/packages/next/src/server/lib/incremental-cache/file-system-cache.ts#L185
87+ // let segmentData: NetlifyCachedAppPageValue['segmentData']
88+ if ( meta . segmentPaths ) {
89+ const segmentsDir = path + RSC_SEGMENTS_DIR_SUFFIX
90+ const segmentData : NetlifyCachedAppPageValue [ 'segmentData' ] = { }
91+
92+ console . log ( 'segment stitching' , {
93+ segmentPaths : meta . segmentPaths ,
94+ path,
95+ } )
96+ await Promise . all (
97+ meta . segmentPaths . map ( async ( segmentPath : string ) => {
98+ const segmentDataFilePath = segmentsDir + segmentPath + RSC_SEGMENT_SUFFIX
99+
100+ segmentData [ segmentPath ] = await readFile ( segmentDataFilePath , 'base64' )
101+ } ) ,
102+ )
103+
104+ meta . segmentData = segmentData
105+ }
106+
81107 return {
82108 kind : 'APP_PAGE' ,
83109 html,
@@ -168,45 +194,52 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void>
168194 : Date . now ( )
169195 const key = routeToFilePath ( route )
170196 let value : NetlifyIncrementalCacheValue
171- switch ( true ) {
172- // Parallel route default layout has no prerendered page
173- case meta . dataRoute ?. endsWith ( '/default.rsc' ) &&
174- ! existsSync ( join ( ctx . publishDir , 'server/app' , `${ key } .html` ) ) :
175- return
176- case meta . dataRoute ?. endsWith ( '.json' ) :
177- if ( manifest . notFoundRoutes . includes ( route ) ) {
178- // if pages router returns 'notFound: true', build won't produce html and json files
197+ try {
198+ switch ( true ) {
199+ // Parallel route default layout has no prerendered page
200+ case meta . dataRoute ?. endsWith ( '/default.rsc' ) &&
201+ ! existsSync ( join ( ctx . publishDir , 'server/app' , `${ key } .html` ) ) :
179202 return
180- }
181- value = await buildPagesCacheValue (
182- join ( ctx . publishDir , 'server/pages' , key ) ,
183- meta . initialRevalidateSeconds ,
184- shouldUseEnumKind ,
185- )
186- break
187- case meta . dataRoute ?. endsWith ( '.rsc' ) :
188- value = await buildAppCacheValue (
189- join ( ctx . publishDir , 'server/app' , key ) ,
190- shouldUseAppPageKind ,
191- )
192- break
193- case meta . dataRoute === null :
194- value = await buildRouteCacheValue (
195- join ( ctx . publishDir , 'server/app' , key ) ,
196- meta . initialRevalidateSeconds ,
197- shouldUseEnumKind ,
198- )
199- break
200- default :
201- throw new Error ( `Unrecognized content: ${ route } ` )
202- }
203+ case meta . dataRoute ?. endsWith ( '.json' ) :
204+ if ( manifest . notFoundRoutes . includes ( route ) ) {
205+ // if pages router returns 'notFound: true', build won't produce html and json files
206+ return
207+ }
203208
204- // Netlify Forms are not support and require a workaround
205- if ( value . kind === 'PAGE' || value . kind === 'PAGES' || value . kind === 'APP_PAGE' ) {
206- verifyNetlifyForms ( ctx , value . html )
207- }
209+ value = await buildPagesCacheValue (
210+ join ( ctx . publishDir , 'server/pages' , key ) ,
211+ meta . initialRevalidateSeconds ,
212+ shouldUseEnumKind ,
213+ )
214+ break
215+ case meta . dataRoute ?. endsWith ( '.rsc' ) :
216+ value = await buildAppCacheValue (
217+ join ( ctx . publishDir , 'server/app' , key ) ,
218+ shouldUseAppPageKind ,
219+ )
220+ break
208221
209- await writeCacheEntry ( key , value , lastModified , ctx )
222+ case meta . dataRoute === null :
223+ value = await buildRouteCacheValue (
224+ join ( ctx . publishDir , 'server/app' , key ) ,
225+ meta . initialRevalidateSeconds ,
226+ shouldUseEnumKind ,
227+ )
228+ break
229+ default :
230+ throw new Error ( `Unrecognized content: ${ route } ` )
231+ }
232+
233+ // Netlify Forms are not support and require a workaround
234+ if ( value . kind === 'PAGE' || value . kind === 'PAGES' || value . kind === 'APP_PAGE' ) {
235+ verifyNetlifyForms ( ctx , value . html )
236+ }
237+
238+ await writeCacheEntry ( key , value , lastModified , ctx )
239+ } catch ( error ) {
240+ console . error ( { key, route } )
241+ throw error
242+ }
210243 } ) ,
211244 ) ,
212245 ...ctx . getFallbacks ( manifest ) . map ( async ( route ) => {
0 commit comments