Skip to content

Commit dfd3c26

Browse files
ijjkvercel[bot]
andauthored
Ensure outputs are correct with cache components in deployment adapters (vercel#87018)
Updates our outputs to ensure we provide correct metadata and ISR pairs when cache components are enabled. --------- Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
1 parent 840643f commit dfd3c26

File tree

11 files changed

+480
-79
lines changed

11 files changed

+480
-79
lines changed

packages/next/src/build/adapter/build-complete.ts

Lines changed: 114 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -174,37 +174,50 @@ export interface AdapterOutput {
174174
/**
175175
* fallback is initial cache data generated during build for a prerender
176176
*/
177-
fallback?: {
178-
/**
179-
* path to the fallback file can be HTML/JSON/RSC
180-
*/
181-
filePath: string
182-
/**
183-
* initialStatus is the status code that should be applied
184-
* when serving the fallback
185-
*/
186-
initialStatus?: number
187-
/**
188-
* initialHeaders are the headers that should be sent when
189-
* serving the fallback
190-
*/
191-
initialHeaders?: Record<string, string | string[]>
192-
/**
193-
* initial expiration is how long until the fallback entry
194-
* is considered expired and no longer valid to serve
195-
*/
196-
initialExpiration?: number
197-
/**
198-
* initial revalidate is how long until the fallback is
199-
* considered stale and should be revalidated
200-
*/
201-
initialRevalidate?: Revalidate
202-
203-
/**
204-
* postponedState is the PPR state when it postponed and is used for resuming
205-
*/
206-
postponedState?: string
207-
}
177+
fallback?:
178+
| {
179+
/**
180+
* path to the fallback file can be HTML/JSON/RSC,
181+
*/
182+
filePath: string
183+
/**
184+
* initialStatus is the status code that should be applied
185+
* when serving the fallback
186+
*/
187+
initialStatus?: number
188+
/**
189+
* initialHeaders are the headers that should be sent when
190+
* serving the fallback
191+
*/
192+
initialHeaders?: Record<string, string | string[]>
193+
/**
194+
* initial expiration is how long until the fallback entry
195+
* is considered expired and no longer valid to serve
196+
*/
197+
initialExpiration?: number
198+
/**
199+
* initial revalidate is how long until the fallback is
200+
* considered stale and should be revalidated
201+
*/
202+
initialRevalidate?: Revalidate
203+
204+
/**
205+
* postponedState is the PPR state when it postponed and is used for resuming
206+
*/
207+
postponedState?: string
208+
}
209+
| {
210+
/*
211+
a fallback filePath can be omitted when postponedState is
212+
present which signals the fallback should just resume with
213+
the postpone state but doesn't have fallback to seed cache
214+
*/
215+
postponedState: string
216+
initialExpiration?: number
217+
initialRevalidate?: Revalidate
218+
initialHeaders?: Record<string, string | string[]>
219+
initialStatus?: number
220+
}
208221
/**
209222
* config related to the route
210223
*/
@@ -1164,7 +1177,6 @@ export async function handleBuildComplete({
11641177
initialRevalidateSeconds: initialRevalidate,
11651178
initialHeaders,
11661179
initialStatus,
1167-
prefetchDataRoute,
11681180
dataRoute,
11691181
renderingMode,
11701182
allowHeader,
@@ -1273,43 +1285,64 @@ export async function handleBuildComplete({
12731285
outputs.prerenders.push(initialOutput)
12741286

12751287
if (dataRoute) {
1276-
let dataFilePath = path.join(
1288+
let dataFilePath: string | undefined = path.join(
12771289
pagesDistDir,
12781290
`${normalizePagePath(route)}.json`
12791291
)
1292+
let postponed = meta.postponed
12801293

12811294
if (isAppPage) {
12821295
// When experimental PPR is enabled, we expect that the data
12831296
// that should be served as a part of the prerender should
12841297
// be from the prefetch data route. If this isn't enabled
12851298
// for ppr, the only way to get the data is from the data
12861299
// route.
1287-
dataFilePath = path.join(
1288-
appDistDir,
1289-
prefetchDataRoute &&
1290-
renderingMode === RenderingMode.PARTIALLY_STATIC
1291-
? prefetchDataRoute
1292-
: dataRoute
1293-
)
1300+
dataFilePath = path.join(appDistDir, dataRoute)
12941301
}
12951302

1296-
outputs.prerenders.push({
1297-
...initialOutput,
1298-
id: dataRoute,
1299-
pathname: dataRoute,
1300-
fallback: isNotFoundTrue
1301-
? undefined
1302-
: {
1303-
...initialOutput.fallback,
1304-
initialHeaders: {
1305-
...initialOutput.fallback?.initialHeaders,
1306-
'content-type': isAppPage
1307-
? rscContentTypeHeader
1308-
: JSON_CONTENT_TYPE_HEADER,
1303+
if (
1304+
renderingMode === RenderingMode.PARTIALLY_STATIC &&
1305+
!(await cachedFilePathCheck(dataFilePath))
1306+
) {
1307+
// TODO: allowQuery should diverge based on app client param
1308+
// parsing flag
1309+
outputs.prerenders.push({
1310+
...initialOutput,
1311+
id: dataRoute,
1312+
pathname: dataRoute,
1313+
fallback: !postponed
1314+
? undefined
1315+
: {
1316+
...initialOutput.fallback,
1317+
postponedState: postponed,
1318+
initialHeaders: {
1319+
...initialOutput.fallback?.initialHeaders,
1320+
'content-type': isAppPage
1321+
? rscContentTypeHeader
1322+
: JSON_CONTENT_TYPE_HEADER,
1323+
},
1324+
filePath: undefined,
13091325
},
1310-
filePath: dataFilePath,
1311-
},
1312-
})
1326+
})
1327+
} else {
1328+
outputs.prerenders.push({
1329+
...initialOutput,
1330+
id: dataRoute,
1331+
pathname: dataRoute,
1332+
fallback: isNotFoundTrue
1333+
? undefined
1334+
: {
1335+
...initialOutput.fallback,
1336+
initialHeaders: {
1337+
...initialOutput.fallback?.initialHeaders,
1338+
'content-type': isAppPage
1339+
? rscContentTypeHeader
1340+
: JSON_CONTENT_TYPE_HEADER,
1341+
},
1342+
filePath: dataFilePath,
1343+
},
1344+
})
1345+
}
13131346
}
13141347

13151348
if (isAppPage) {
@@ -1325,13 +1358,16 @@ export async function handleBuildComplete({
13251358
fallbackRevalidate,
13261359
fallbackHeaders,
13271360
fallbackStatus,
1361+
fallbackSourceRoute,
13281362
allowHeader,
13291363
dataRoute,
13301364
renderingMode,
13311365
experimentalBypassFor,
13321366
} = prerenderManifest.dynamicRoutes[dynamicRoute]
13331367

1334-
const isAppPage = Boolean(appOutputMap[dynamicRoute])
1368+
const srcRoute = fallbackSourceRoute || dynamicRoute
1369+
const parentOutput = getParentOutput(srcRoute, dynamicRoute)
1370+
const isAppPage = Boolean(appOutputMap[srcRoute])
13351371

13361372
const allowQuery = Object.values(
13371373
routesManifest.dynamicRoutes.find(
@@ -1344,7 +1380,7 @@ export async function handleBuildComplete({
13441380
id: dynamicRoute,
13451381
type: AdapterOutputType.PRERENDER,
13461382
pathname: dynamicRoute,
1347-
parentOutputId: getParentOutput(dynamicRoute, dynamicRoute).id,
1383+
parentOutputId: parentOutput.id,
13481384
groupId: prerenderGroupId,
13491385
config: {
13501386
allowQuery,
@@ -1380,7 +1416,25 @@ export async function handleBuildComplete({
13801416
await handleAppMeta(dynamicRoute, initialOutput, meta)
13811417
}
13821418

1383-
if (dataRoute) {
1419+
if (renderingMode === RenderingMode.PARTIALLY_STATIC) {
1420+
outputs.prerenders.push({
1421+
...initialOutput,
1422+
id: `${dynamicRoute}.rsc`,
1423+
pathname: `${dynamicRoute}.rsc`,
1424+
fallback: meta.postponed
1425+
? {
1426+
...initialOutput.fallback,
1427+
postponedState: meta.postponed,
1428+
initialHeaders: {
1429+
...initialOutput.fallback?.initialHeaders,
1430+
'content-type': isAppPage
1431+
? rscContentTypeHeader
1432+
: JSON_CONTENT_TYPE_HEADER,
1433+
},
1434+
}
1435+
: undefined,
1436+
})
1437+
} else if (dataRoute) {
13841438
outputs.prerenders.push({
13851439
...initialOutput,
13861440
id: dataRoute,
@@ -1521,7 +1575,7 @@ export async function handleBuildComplete({
15211575
route.page
15221576
) + getDestinationQuery(route.routeKeys)
15231577

1524-
if (appPageKeys && appPageKeys.length > 0 && config.cacheComponents) {
1578+
if (appPageKeys && appPageKeys.length > 0) {
15251579
// If we have fallback root params (implying we've already
15261580
// emitted a rewrite for the /_tree request), or if the route
15271581
// has PPR enabled and client param parsing is enabled, then

packages/next/src/build/define-env.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,6 @@ export function getDefineEnv({
147147
: process.env.NEXT_RSPACK
148148
? 'Rspack'
149149
: 'Webpack',
150-
// minimal mode is enforced when an adapter is configured
151-
'process.env.MINIMAL_MODE': Boolean(config.experimental.adapterPath),
152150
// TODO: enforce `NODE_ENV` on `process.env`, and add a test:
153151
'process.env.NODE_ENV':
154152
dev || config.experimental.allowDevelopmentBuild

packages/next/src/build/templates/app-page.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,7 @@ export async function handler(
121121
if (routeModule.isDev) {
122122
addRequestMeta(req, 'devRequestTimingInternalsEnd', process.hrtime.bigint())
123123
}
124-
const isMinimalMode = Boolean(
125-
process.env.MINIMAL_MODE || getRequestMeta(req, 'minimalMode')
126-
)
124+
const isMinimalMode = Boolean(getRequestMeta(req, 'minimalMode'))
127125

128126
let srcPage = 'VAR_DEFINITION_PAGE'
129127

packages/next/src/build/templates/app-route.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,7 @@ export async function handler(
280280
}
281281
})
282282
}
283-
const isMinimalMode = Boolean(
284-
process.env.MINIMAL_MODE || getRequestMeta(req, 'minimalMode')
285-
)
283+
const isMinimalMode = Boolean(getRequestMeta(req, 'minimalMode'))
286284

287285
const handleResponse = async (currentSpan?: Span) => {
288286
const responseGenerator: ResponseGenerator = async ({

packages/next/src/server/route-modules/pages/pages-handler.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,7 @@ export const getHandler = ({
102102
return
103103
}
104104

105-
const isMinimalMode = Boolean(
106-
process.env.MINIMAL_MODE || getRequestMeta(req, 'minimalMode')
107-
)
105+
const isMinimalMode = Boolean(getRequestMeta(req, 'minimalMode'))
108106

109107
const render404 = async () => {
110108
// TODO: should route-module itself handle rendering the 404

packages/next/src/server/route-modules/route-module.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -965,10 +965,7 @@ export abstract class RouteModule<
965965

966966
public getResponseCache(req: IncomingMessage | BaseNextRequest) {
967967
if (!this.responseCache) {
968-
const minimalMode =
969-
(Boolean(process.env.MINIMAL_MODE) ||
970-
getRequestMeta(req, 'minimalMode')) ??
971-
false
968+
const minimalMode = getRequestMeta(req, 'minimalMode') ?? false
972969
this.responseCache = new ResponseCache(minimalMode)
973970
}
974971
return this.responseCache

0 commit comments

Comments
 (0)