@@ -2,6 +2,8 @@ import { existsSync } from 'node:fs'
22import { mkdir , readFile , writeFile } from 'node:fs/promises'
33import { join } from 'node:path'
44
5+ import { trace } from '@opentelemetry/api'
6+ import { wrapTracer } from '@opentelemetry/api/experimental'
57import { glob } from 'fast-glob'
68import type { CacheHandlerValue } from 'next/dist/server/lib/incremental-cache/index.js'
79import type { IncrementalCacheValue } from 'next/dist/server/response-cache/types.js'
@@ -14,6 +16,8 @@ type CachedPageValue = Extract<IncrementalCacheValue, { kind: 'PAGE' }>
1416type CachedRouteValue = Extract < IncrementalCacheValue , { kind : 'ROUTE' } >
1517type CachedFetchValue = Extract < IncrementalCacheValue , { kind : 'FETCH' } >
1618
19+ const tracer = wrapTracer ( trace . getTracer ( 'Next runtime' ) )
20+
1721/**
1822 * Write a cache entry to the blob upload directory.
1923 */
@@ -79,61 +83,63 @@ const buildFetchCacheValue = async (path: string): Promise<CachedFetchValue> =>
7983 * Upload prerendered content to the blob store
8084 */
8185export const copyPrerenderedContent = async ( ctx : PluginContext ) : Promise < void > => {
82- try {
83- // ensure the blob directory exists
84- await mkdir ( ctx . blobDir , { recursive : true } )
85- // read prerendered content and build JSON key/values for the blob store
86- const manifest = await ctx . getPrerenderManifest ( )
87-
88- const limitConcurrentPrerenderContentHandling = pLimit ( 10 )
89-
90- await Promise . all (
91- Object . entries ( manifest . routes ) . map (
92- ( [ route , meta ] ) : Promise < void > =>
93- limitConcurrentPrerenderContentHandling ( async ( ) => {
94- const lastModified = meta . initialRevalidateSeconds
95- ? Date . now ( ) - 31536000000
96- : Date . now ( )
97- const key = routeToFilePath ( route )
98- let value : IncrementalCacheValue
99- switch ( true ) {
100- // Parallel route default layout has no prerendered page
101- case meta . dataRoute ?. endsWith ( '/default.rsc' ) &&
102- ! existsSync ( join ( ctx . publishDir , 'server/app' , `${ key } .html` ) ) :
103- return
104- case meta . dataRoute ?. endsWith ( '.json' ) :
105- if ( manifest . notFoundRoutes . includes ( route ) ) {
106- // if pages router returns 'notFound: true', build won't produce html and json files
86+ return tracer . withActiveSpan ( 'copyPrerenderedContent' , async ( ) => {
87+ try {
88+ // ensure the blob directory exists
89+ await mkdir ( ctx . blobDir , { recursive : true } )
90+ // read prerendered content and build JSON key/values for the blob store
91+ const manifest = await ctx . getPrerenderManifest ( )
92+
93+ const limitConcurrentPrerenderContentHandling = pLimit ( 10 )
94+
95+ await Promise . all (
96+ Object . entries ( manifest . routes ) . map (
97+ ( [ route , meta ] ) : Promise < void > =>
98+ limitConcurrentPrerenderContentHandling ( async ( ) => {
99+ const lastModified = meta . initialRevalidateSeconds
100+ ? Date . now ( ) - 31536000000
101+ : Date . now ( )
102+ const key = routeToFilePath ( route )
103+ let value : IncrementalCacheValue
104+ switch ( true ) {
105+ // Parallel route default layout has no prerendered page
106+ case meta . dataRoute ?. endsWith ( '/default.rsc' ) &&
107+ ! existsSync ( join ( ctx . publishDir , 'server/app' , `${ key } .html` ) ) :
107108 return
108- }
109- value = await buildPagesCacheValue ( join ( ctx . publishDir , 'server/pages' , key ) )
110- break
111- case meta . dataRoute ?. endsWith ( '.rsc' ) :
112- value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
113- break
114- case meta . dataRoute === null :
115- value = await buildRouteCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
116- break
117- default :
118- throw new Error ( `Unrecognized content: ${ route } ` )
119- }
120-
121- await writeCacheEntry ( key , value , lastModified , ctx )
122- } ) ,
123- ) ,
124- )
125-
126- // app router 404 pages are not in the prerender manifest
127- // so we need to check for them manually
128- if ( existsSync ( join ( ctx . publishDir , `server/app/_not-found.html` ) ) ) {
129- const lastModified = Date . now ( )
130- const key = '/404'
131- const value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app/_not-found' ) )
132- await writeCacheEntry ( key , value , lastModified , ctx )
109+ case meta . dataRoute ?. endsWith ( '.json' ) :
110+ if ( manifest . notFoundRoutes . includes ( route ) ) {
111+ // if pages router returns 'notFound: true', build won't produce html and json files
112+ return
113+ }
114+ value = await buildPagesCacheValue ( join ( ctx . publishDir , 'server/pages' , key ) )
115+ break
116+ case meta . dataRoute ?. endsWith ( '.rsc' ) :
117+ value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
118+ break
119+ case meta . dataRoute === null :
120+ value = await buildRouteCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
121+ break
122+ default :
123+ throw new Error ( `Unrecognized content: ${ route } ` )
124+ }
125+
126+ await writeCacheEntry ( key , value , lastModified , ctx )
127+ } ) ,
128+ ) ,
129+ )
130+
131+ // app router 404 pages are not in the prerender manifest
132+ // so we need to check for them manually
133+ if ( existsSync ( join ( ctx . publishDir , `server/app/_not-found.html` ) ) ) {
134+ const lastModified = Date . now ( )
135+ const key = '/404'
136+ const value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app/_not-found' ) )
137+ await writeCacheEntry ( key , value , lastModified , ctx )
138+ }
139+ } catch ( error ) {
140+ ctx . failBuild ( 'Failed assembling prerendered content for upload' , error )
133141 }
134- } catch ( error ) {
135- ctx . failBuild ( 'Failed assembling prerendered content for upload' , error )
136- }
142+ } )
137143}
138144
139145/**
0 commit comments