-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
decide wether to use APP_PAGE or PAGE kind based on actual next version
- Loading branch information
Showing
1 changed file
with
43 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ import { trace } from '@opentelemetry/api' | |
import { wrapTracer } from '@opentelemetry/api/experimental' | ||
import { glob } from 'fast-glob' | ||
import pLimit from 'p-limit' | ||
import { satisfies } from 'semver' | ||
|
||
import { encodeBlobKey } from '../../shared/blobkey.js' | ||
import type { | ||
|
@@ -53,41 +54,40 @@ const buildPagesCacheValue = async (path: string): Promise<NetlifyCachedPageValu | |
|
||
const buildAppCacheValue = async ( | ||
path: string, | ||
shouldUseAppPageKind: boolean, | ||
): Promise<NetlifyCachedAppPageValue | NetlifyCachedPageValue> => { | ||
const meta = JSON.parse(await readFile(`${path}.meta`, 'utf-8')) | ||
const html = await readFile(`${path}.html`, 'utf-8') | ||
|
||
// TODO: check actual next version and not rely on env var set by tests | ||
const useOldStuff = process.env.NEXT_VERSION !== 'canary' | ||
if (useOldStuff) { | ||
const rsc = await readFile(`${path}.rsc`, 'utf-8').catch(() => | ||
readFile(`${path}.prefetch.rsc`, 'utf-8'), | ||
) | ||
|
||
// Next < v14.2.0 does not set meta.status when notFound() is called directly on a page | ||
// Exclude Parallel routes, they are 404s when visited directly | ||
if ( | ||
!meta.status && | ||
rsc.includes('NEXT_NOT_FOUND') && | ||
!meta.headers['x-next-cache-tags'].includes('/@') | ||
) { | ||
meta.status = 404 | ||
} | ||
// supporting both old and new cache kind for App Router pages - https://github.com/vercel/next.js/pull/65988 | ||
if (shouldUseAppPageKind) { | ||
return { | ||
kind: 'PAGE', | ||
kind: 'APP_PAGE', | ||
html, | ||
pageData: rsc, | ||
rscData: await readFile(`${path}.rsc`, 'base64').catch(() => | ||
readFile(`${path}.prefetch.rsc`, 'base64'), | ||
), | ||
...meta, | ||
} | ||
} | ||
|
||
// use new stuff | ||
const rsc = await readFile(`${path}.rsc`, 'utf-8').catch(() => | ||
readFile(`${path}.prefetch.rsc`, 'utf-8'), | ||
) | ||
|
||
// Next < v14.2.0 does not set meta.status when notFound() is called directly on a page | ||
// Exclude Parallel routes, they are 404s when visited directly | ||
if ( | ||
!meta.status && | ||
rsc.includes('NEXT_NOT_FOUND') && | ||
!meta.headers['x-next-cache-tags'].includes('/@') | ||
) { | ||
meta.status = 404 | ||
} | ||
return { | ||
kind: 'APP_PAGE', | ||
kind: 'PAGE', | ||
html, | ||
rscData: await readFile(`${path}.rsc`, 'base64').catch(() => | ||
readFile(`${path}.prefetch.rsc`, 'base64'), | ||
), | ||
pageData: rsc, | ||
...meta, | ||
} | ||
} | ||
|
@@ -120,6 +120,18 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void> | |
|
||
const limitConcurrentPrerenderContentHandling = pLimit(10) | ||
|
||
// https://github.com/vercel/next.js/pull/65988 introduced Cache kind specific to pages in App Router (`APP_PAGE`). | ||
// Before this change there was common kind for both Pages router and App router pages | ||
// so we check Next.js version to decide how to generate cache values for App Router pages. | ||
// Note: at time of writing this code, released 15@rc uses old kind for App Router pages, while [email protected] and newer canaries use new kind. | ||
// Looking at 15@rc release branch it was merging `canary` branch in, so the version constraint assumes that future 15@rc (and 15@latest) versions | ||
// will use new kind for App Router pages. | ||
const shouldUseAppPageKind = ctx.nextVersion | ||
? satisfies(ctx.nextVersion, '>=15.0.0-canary.13 <15.0.0-d || >15.0.0-rc.0', { | ||
includePrerelease: true, | ||
}) | ||
: false | ||
|
||
await Promise.all( | ||
Object.entries(manifest.routes).map( | ||
([route, meta]): Promise<void> => | ||
|
@@ -142,7 +154,10 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void> | |
value = await buildPagesCacheValue(join(ctx.publishDir, 'server/pages', key)) | ||
break | ||
case meta.dataRoute?.endsWith('.rsc'): | ||
value = await buildAppCacheValue(join(ctx.publishDir, 'server/app', key)) | ||
value = await buildAppCacheValue( | ||
join(ctx.publishDir, 'server/app', key), | ||
shouldUseAppPageKind, | ||
) | ||
break | ||
case meta.dataRoute === null: | ||
value = await buildRouteCacheValue( | ||
|
@@ -164,7 +179,10 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void> | |
if (existsSync(join(ctx.publishDir, `server/app/_not-found.html`))) { | ||
const lastModified = Date.now() | ||
const key = '/404' | ||
const value = await buildAppCacheValue(join(ctx.publishDir, 'server/app/_not-found')) | ||
const value = await buildAppCacheValue( | ||
join(ctx.publishDir, 'server/app/_not-found'), | ||
shouldUseAppPageKind, | ||
) | ||
await writeCacheEntry(key, value, lastModified, ctx) | ||
} | ||
} catch (error) { | ||
|