@@ -6,11 +6,10 @@ import * as Log from '../output/log'
6
6
import globOriginal from 'next/dist/compiled/glob'
7
7
import { interopDefault } from '../../lib/interop-default'
8
8
import type { AdapterOutputs , NextAdapter } from '../../server/config-shared'
9
- import {
10
- RouteType ,
11
- type FunctionsConfigManifest ,
12
- type PrerenderManifest ,
13
- type RoutesManifest ,
9
+ import type {
10
+ FunctionsConfigManifest ,
11
+ PrerenderManifest ,
12
+ RoutesManifest ,
14
13
} from '..'
15
14
import type {
16
15
EdgeFunctionDefinition ,
@@ -19,6 +18,8 @@ import type {
19
18
import { isMiddlewareFilename } from '../utils'
20
19
import { normalizePagePath } from '../../shared/lib/page-path/normalize-page-path'
21
20
import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths'
21
+ import { AdapterOutputType } from '../../shared/lib/constants'
22
+ import { RenderingMode } from '../rendering-mode'
22
23
23
24
const glob = promisify ( globOriginal )
24
25
@@ -33,8 +34,9 @@ export async function handleBuildComplete({
33
34
hasInstrumentationHook,
34
35
requiredServerFiles,
35
36
routesManifest,
36
- // prerenderManifest,
37
+ prerenderManifest,
37
38
middlewareManifest,
39
+ functionsConfigManifest,
38
40
} : {
39
41
dir : string
40
42
distDir : string
@@ -68,7 +70,7 @@ export async function handleBuildComplete({
68
70
const pathname = path . posix . join ( '/_next/static' , file )
69
71
const filePath = path . join ( distDir , 'static' , file )
70
72
outputs . push ( {
71
- type : RouteType . STATIC_FILE ,
73
+ type : AdapterOutputType . STATIC_FILE ,
72
74
id : path . join ( 'static' , file ) ,
73
75
pathname,
74
76
filePath,
@@ -126,19 +128,19 @@ export async function handleBuildComplete({
126
128
page : EdgeFunctionDefinition ,
127
129
isMiddleware : boolean = false
128
130
) {
129
- let type = RouteType . PAGES
131
+ let type = AdapterOutputType . PAGES
130
132
const isAppPrefix = page . page . startsWith ( 'app/' )
131
133
const isAppPage = isAppPrefix && page . page . endsWith ( '/page' )
132
134
const isAppRoute = isAppPrefix && page . page . endsWith ( '/route' )
133
135
134
136
if ( isMiddleware ) {
135
- type = RouteType . MIDDLEWARE
137
+ type = AdapterOutputType . MIDDLEWARE
136
138
} else if ( isAppPage ) {
137
- type = RouteType . APP_PAGE
139
+ type = AdapterOutputType . APP_PAGE
138
140
} else if ( isAppRoute ) {
139
- type = RouteType . APP_ROUTE
141
+ type = AdapterOutputType . APP_ROUTE
140
142
} else if ( page . page . startsWith ( '/api' ) ) {
141
- type = RouteType . PAGES_API
143
+ type = AdapterOutputType . PAGES_API
142
144
}
143
145
144
146
const output : AdapterOutputs [ 0 ] = {
@@ -155,6 +157,12 @@ export async function handleBuildComplete({
155
157
) ,
156
158
assets : { } ,
157
159
type,
160
+ config :
161
+ type === AdapterOutputType . MIDDLEWARE
162
+ ? {
163
+ matchers : page . matchers ,
164
+ }
165
+ : { } ,
158
166
}
159
167
160
168
function handleFile ( file : string ) {
@@ -188,6 +196,7 @@ export async function handleBuildComplete({
188
196
for ( const page of Object . values ( middlewareManifest . functions ) ) {
189
197
edgeFunctionHandlers . push ( handleEdgeFunction ( page ) )
190
198
}
199
+ const pageOutputMap : Record < string , AdapterOutputs [ 0 ] > = { }
191
200
192
201
for ( const page of pageKeys ) {
193
202
if ( middlewareManifest . functions . hasOwnProperty ( page ) ) {
@@ -204,35 +213,50 @@ export async function handleBuildComplete({
204
213
const pageTraceFile = `${ pageFile } .nft.json`
205
214
const assets = await handleTraceFiles ( pageTraceFile ) . catch ( ( err ) => {
206
215
if ( err . code !== 'ENOENT' || ( page !== '/404' && page !== '/500' ) ) {
207
- Log . warn ( `Failed to copy traced files for ${ pageFile } ` , err )
216
+ Log . warn ( `Failed to locate traced assets for ${ pageFile } ` , err )
208
217
}
209
218
return { } as Record < string , string >
210
219
} )
220
+ const functionConfig = functionsConfigManifest . functions [ route ] || { }
211
221
212
- outputs . push ( {
222
+ const output : AdapterOutputs [ 0 ] = {
213
223
id : route ,
214
- type : page . startsWith ( '/api' ) ? RouteType . PAGES_API : RouteType . PAGES ,
224
+ type : page . startsWith ( '/api' )
225
+ ? AdapterOutputType . PAGES_API
226
+ : AdapterOutputType . PAGES ,
215
227
filePath : pageTraceFile . replace ( / \. n f t \. j s o n $ / , '' ) ,
216
228
pathname : route ,
217
229
assets,
218
230
runtime : 'nodejs' ,
219
- } )
231
+ config : {
232
+ maxDuration : functionConfig . maxDuration ,
233
+ preferredRegion : functionConfig . regions ,
234
+ } ,
235
+ }
236
+ pageOutputMap [ page ] = output
237
+ outputs . push ( output )
220
238
}
221
239
222
240
if ( hasNodeMiddleware ) {
223
241
const middlewareFile = path . join ( distDir , 'server' , 'middleware.js' )
224
242
const middlewareTrace = `${ middlewareFile } .nft.json`
225
243
const assets = await handleTraceFiles ( middlewareTrace )
244
+ const functionConfig =
245
+ functionsConfigManifest . functions [ '/_middleware' ] || { }
226
246
227
247
outputs . push ( {
228
248
pathname : '/_middleware' ,
229
249
id : '/_middleware' ,
230
250
assets,
231
- type : RouteType . MIDDLEWARE ,
251
+ type : AdapterOutputType . MIDDLEWARE ,
232
252
runtime : 'nodejs' ,
233
253
filePath : middlewareFile ,
254
+ config : {
255
+ matchers : functionConfig . matchers ,
256
+ } ,
234
257
} )
235
258
}
259
+ const appOutputMap : Record < string , AdapterOutputs [ 0 ] > = { }
236
260
237
261
if ( appPageKeys ) {
238
262
for ( const page of appPageKeys ) {
@@ -246,21 +270,180 @@ export async function handleBuildComplete({
246
270
Log . warn ( `Failed to copy traced files for ${ pageFile } ` , err )
247
271
return { } as Record < string , string >
248
272
} )
273
+ const functionConfig =
274
+ functionsConfigManifest . functions [ normalizedPage ] || { }
249
275
250
- outputs . push ( {
276
+ const output : AdapterOutputs [ 0 ] = {
251
277
pathname : normalizedPage ,
252
278
id : normalizedPage ,
253
279
assets,
254
280
type : page . endsWith ( '/route' )
255
- ? RouteType . APP_ROUTE
256
- : RouteType . APP_PAGE ,
281
+ ? AdapterOutputType . APP_ROUTE
282
+ : AdapterOutputType . APP_PAGE ,
257
283
runtime : 'nodejs' ,
258
284
filePath : pageFile ,
285
+ config : {
286
+ maxDuration : functionConfig . maxDuration ,
287
+ preferredRegion : functionConfig . regions ,
288
+ } ,
289
+ }
290
+ appOutputMap [ normalizedPage ] = output
291
+ outputs . push ( output )
292
+ }
293
+ }
294
+
295
+ const getParentOutput = ( srcRoute : string , childRoute : string ) => {
296
+ const parentOutput = pageOutputMap [ srcRoute ] || appOutputMap [ srcRoute ]
297
+
298
+ if ( ! parentOutput ) {
299
+ console . error ( {
300
+ appOutputs : Object . keys ( appOutputMap ) ,
301
+ pageOutputs : Object . keys ( pageOutputMap ) ,
302
+ } )
303
+ throw new Error (
304
+ `Invariant: failed to find source route ${ srcRoute } for prerender ${ childRoute } `
305
+ )
306
+ }
307
+ return parentOutput
308
+ }
309
+
310
+ for ( const route in prerenderManifest . routes ) {
311
+ const {
312
+ initialExpireSeconds : initialExpiration ,
313
+ initialRevalidateSeconds : initialRevalidate ,
314
+ initialHeaders,
315
+ initialStatus,
316
+ prefetchDataRoute,
317
+ dataRoute,
318
+ renderingMode,
319
+ } = prerenderManifest . routes [ route ]
320
+
321
+ const srcRoute = prerenderManifest . routes [ route ] . srcRoute || route
322
+ const isAppPage = dataRoute ?. endsWith ( '.rsc' )
323
+
324
+ const filePath = path . join (
325
+ distDir ,
326
+ 'server' ,
327
+ isAppPage ? 'app' : 'pages' ,
328
+ `${ route } .html`
329
+ )
330
+ const initialOutput = {
331
+ id : route ,
332
+ type : AdapterOutputType . PRERENDER ,
333
+ pathname : route ,
334
+ parentOutputId : getParentOutput ( srcRoute , route ) . id ,
335
+ fallback : {
336
+ filePath,
337
+ initialStatus,
338
+ initialHeaders,
339
+ initialExpiration,
340
+ initialRevalidate,
341
+ } ,
342
+ config : {
343
+ renderingMode,
344
+ } ,
345
+ }
346
+ outputs . push ( initialOutput )
347
+
348
+ if ( dataRoute ) {
349
+ let dataFilePath = path . join (
350
+ distDir ,
351
+ 'server' ,
352
+ 'pages' ,
353
+ `${ route } .json`
354
+ )
355
+
356
+ if ( isAppPage ) {
357
+ // When experimental PPR is enabled, we expect that the data
358
+ // that should be served as a part of the prerender should
359
+ // be from the prefetch data route. If this isn't enabled
360
+ // for ppr, the only way to get the data is from the data
361
+ // route.
362
+ dataFilePath = path . join (
363
+ distDir ,
364
+ 'server' ,
365
+ 'app' ,
366
+ prefetchDataRoute &&
367
+ renderingMode === RenderingMode . PARTIALLY_STATIC
368
+ ? prefetchDataRoute
369
+ : dataRoute
370
+ )
371
+ }
372
+
373
+ outputs . push ( {
374
+ ...initialOutput ,
375
+ id : dataRoute ,
376
+ pathname : dataRoute ,
377
+ fallback : {
378
+ ...initialOutput . fallback ,
379
+ filePath : dataFilePath ,
380
+ } ,
259
381
} )
260
382
}
261
383
}
262
384
263
- // TODO: prerender assets
385
+ for ( const dynamicRoute in prerenderManifest . dynamicRoutes ) {
386
+ const {
387
+ fallback,
388
+ fallbackExpire,
389
+ fallbackRevalidate,
390
+ fallbackHeaders,
391
+ fallbackStatus,
392
+ dataRoute,
393
+ } = prerenderManifest . dynamicRoutes [ dynamicRoute ]
394
+
395
+ const isAppPage = dataRoute ?. endsWith ( '.rsc' )
396
+
397
+ const initialOutput = {
398
+ id : dynamicRoute ,
399
+ type : AdapterOutputType . PRERENDER ,
400
+ pathname : dynamicRoute ,
401
+ parentOutputId : getParentOutput ( dynamicRoute , dynamicRoute ) . id ,
402
+ fallback :
403
+ typeof fallback === 'string'
404
+ ? {
405
+ filePath : path . join (
406
+ distDir ,
407
+ 'server' ,
408
+ isAppPage ? 'app' : 'pages' ,
409
+ fallback
410
+ ) ,
411
+ initialStatus : fallbackStatus ,
412
+ initialHeaders : fallbackHeaders ,
413
+ initialExpiration : fallbackExpire ,
414
+ initialRevalidate : fallbackRevalidate ,
415
+ }
416
+ : undefined ,
417
+ }
418
+ outputs . push ( initialOutput )
419
+
420
+ if ( dataRoute ) {
421
+ outputs . push ( {
422
+ ...initialOutput ,
423
+ id : dataRoute ,
424
+ pathname : dataRoute ,
425
+ } )
426
+ }
427
+ }
428
+
429
+ // TODO: should these be normal outputs or meta on associated routes?
430
+ // for (const route of prerenderManifest.notFoundRoutes) {
431
+ // // The fallback here is the 404 page if statically generated
432
+ // // if it is not then the fallback is empty and it is generated
433
+ // // at runtime
434
+
435
+ // outputs.push({
436
+ // id: route,
437
+ // type: OutputType.PRERENDER,
438
+ // pathname: route,
439
+ // runtime: 'nodejs',
440
+ // fallback: {
441
+ // filePath: '',
442
+ // initialStatus: 404,
443
+ // initialHeaders: {},
444
+ // },
445
+ // })
446
+ // }
264
447
265
448
await adapterMod . onBuildComplete ( {
266
449
routes : {
0 commit comments