From bb734c03c68634f48670296a7ea3463da43d654e Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Fri, 14 Jun 2024 13:01:05 +0200 Subject: [PATCH] decide wether to use APP_PAGE or PAGE kind based on actual next version --- src/build/content/prerendered.ts | 68 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/src/build/content/prerendered.ts b/src/build/content/prerendered.ts index 14dcab8972..727044b69c 100644 --- a/src/build/content/prerendered.ts +++ b/src/build/content/prerendered.ts @@ -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 => { 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 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 15.0.0@canary.13 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 => @@ -142,7 +154,10 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise 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 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) {