fix: only generate prefetch rsc for ppr enabled routes (#66395)
This adds details for every ISR cache request if the page being requested supports PPR. If it does, it'll attempt to load the `.prefetch.rsc` payload instead of the `.rsc` payload. This corrects a bug that was present in deployed environments. This additionally refactors the `isAppPPREnabled` out of most of the application, as it's only used to determine if we should add to the `prefetchDataRoute` fields in the `prerender-manifest.json`. To support loading the prefetch file or not, we pass the `isRoutePPREnabled` through with the cache get/set operations instead. x-slack-ref: https://vercel.slack.com/archives/C075MSFK9ML/p1717094328986429
This commit is contained in:
parent
c5b39e31fd
commit
be7d0c970e
24 changed files with 196 additions and 47 deletions
|
@ -1820,7 +1820,6 @@ export default async function build(
|
|||
minimalMode: ciEnvironment.hasNextSupport,
|
||||
allowedRevalidateHeaderKeys:
|
||||
config.experimental.allowedRevalidateHeaderKeys,
|
||||
isAppPPREnabled,
|
||||
})
|
||||
|
||||
incrementalCacheIpcPort = cacheInitialization.ipcPort
|
||||
|
@ -2794,8 +2793,10 @@ export default async function build(
|
|||
}
|
||||
|
||||
let prefetchDataRoute: string | null | undefined
|
||||
// We write the `.prefetch.rsc` when the app has PPR enabled, so
|
||||
// always add the prefetch data route to the manifest.
|
||||
// While we may only write the `.rsc` when the route does not
|
||||
// have PPR enabled, we still want to generate the route when
|
||||
// deployed so it doesn't 404. If the app has PPR enabled, we
|
||||
// should add this key.
|
||||
if (!isRouteHandler && isAppPPREnabled) {
|
||||
prefetchDataRoute = path.posix.join(
|
||||
`${normalizedRoute}${RSC_PREFETCH_SUFFIX}`
|
||||
|
@ -2868,8 +2869,10 @@ export default async function build(
|
|||
|
||||
let prefetchDataRoute: string | undefined
|
||||
|
||||
// We write the `.prefetch.rsc` when the app has PPR enabled, so
|
||||
// always add the prefetch data route to the manifest.
|
||||
// While we may only write the `.rsc` when the route does not
|
||||
// have PPR enabled, we still want to generate the route when
|
||||
// deployed so it doesn't 404. If the app has PPR enabled, we
|
||||
// should add this key.
|
||||
if (!isRouteHandler && isAppPPREnabled) {
|
||||
prefetchDataRoute = path.posix.join(
|
||||
`${normalizedRoute}${RSC_PREFETCH_SUFFIX}`
|
||||
|
|
|
@ -1379,7 +1379,6 @@ export async function buildAppStaticPaths({
|
|||
CurCacheHandler: CacheHandler,
|
||||
requestHeaders,
|
||||
minimalMode: ciEnvironment.hasNextSupport,
|
||||
isAppPPREnabled: false,
|
||||
})
|
||||
|
||||
return StaticGenerationAsyncStorageWrapper.wrap(
|
||||
|
|
|
@ -14,7 +14,6 @@ export async function createIncrementalCache({
|
|||
distDir,
|
||||
dir,
|
||||
enabledDirectories,
|
||||
isAppPPREnabled,
|
||||
flushToDisk,
|
||||
}: {
|
||||
cacheHandler?: string
|
||||
|
@ -23,7 +22,6 @@ export async function createIncrementalCache({
|
|||
distDir: string
|
||||
dir: string
|
||||
enabledDirectories: NextEnabledDirectories
|
||||
isAppPPREnabled: boolean
|
||||
flushToDisk?: boolean
|
||||
}) {
|
||||
// Custom cache handler overrides.
|
||||
|
@ -60,7 +58,6 @@ export async function createIncrementalCache({
|
|||
serverDistDir: path.join(distDir, 'server'),
|
||||
CurCacheHandler: CacheHandler,
|
||||
minimalMode: hasNextSupport,
|
||||
isAppPPREnabled,
|
||||
})
|
||||
|
||||
;(globalThis as any).__incrementalCache = incrementalCache
|
||||
|
|
|
@ -55,7 +55,6 @@ import { validateRevalidate } from '../server/lib/patch-fetch'
|
|||
import { TurborepoAccessTraceResult } from '../build/turborepo-access-trace'
|
||||
import { createProgress } from '../build/progress'
|
||||
import type { DeepReadonly } from '../shared/lib/deep-readonly'
|
||||
import { checkIsAppPPREnabled } from '../server/lib/experimental/ppr'
|
||||
|
||||
export class ExportError extends Error {
|
||||
code = 'NEXT_EXPORT_ERROR'
|
||||
|
@ -358,7 +357,6 @@ export async function exportAppImpl(
|
|||
strictNextHead: nextConfig.experimental.strictNextHead ?? true,
|
||||
deploymentId: nextConfig.deploymentId,
|
||||
experimental: {
|
||||
isAppPPREnabled: checkIsAppPPREnabled(nextConfig.experimental.ppr),
|
||||
clientTraceMetadata: nextConfig.experimental.clientTraceMetadata,
|
||||
swrDelta: nextConfig.swrDelta,
|
||||
after: nextConfig.experimental.after ?? false,
|
||||
|
|
|
@ -95,7 +95,7 @@ export async function exportAppPage(
|
|||
// instead of the standard rsc. This is because the standard rsc will
|
||||
// contain the dynamic data. We do this if any routes have PPR enabled so
|
||||
// that the cache read/write is the same.
|
||||
else if (renderOpts.experimental.isAppPPREnabled) {
|
||||
else if (renderOpts.experimental.isRoutePPREnabled) {
|
||||
// If PPR is enabled, we should emit the flight data as the prefetch
|
||||
// payload.
|
||||
await fileWriter(
|
||||
|
|
|
@ -231,7 +231,6 @@ async function exportPageImpl(
|
|||
distDir,
|
||||
dir,
|
||||
enabledDirectories,
|
||||
isAppPPREnabled: input.renderOpts.experimental.isAppPPREnabled,
|
||||
// skip writing to disk in minimal mode for now, pending some
|
||||
// changes to better support it
|
||||
flushToDisk: !hasNextSupport,
|
||||
|
|
|
@ -160,11 +160,6 @@ export interface RenderOptsPartial {
|
|||
params?: ParsedUrlQuery
|
||||
isPrefetch?: boolean
|
||||
experimental: {
|
||||
/**
|
||||
* When true, some routes support partial prerendering (PPR).
|
||||
*/
|
||||
isAppPPREnabled: boolean
|
||||
|
||||
/**
|
||||
* When true, it indicates that the current page supports partial
|
||||
* prerendering.
|
||||
|
|
|
@ -426,6 +426,8 @@ export default abstract class Server<
|
|||
readonly data: NextDataPathnameNormalizer | undefined
|
||||
}
|
||||
|
||||
private readonly isAppPPREnabled: boolean
|
||||
|
||||
public constructor(options: ServerOptions) {
|
||||
const {
|
||||
dir = '.',
|
||||
|
@ -491,7 +493,7 @@ export default abstract class Server<
|
|||
|
||||
this.enabledDirectories = this.getEnabledDirectories(dev)
|
||||
|
||||
const isAppPPREnabled =
|
||||
this.isAppPPREnabled =
|
||||
this.enabledDirectories.app &&
|
||||
checkIsAppPPREnabled(this.nextConfig.experimental.ppr)
|
||||
|
||||
|
@ -500,7 +502,7 @@ export default abstract class Server<
|
|||
// mode as otherwise that route is not exposed external to the server as
|
||||
// we instead only rely on the headers.
|
||||
postponed:
|
||||
isAppPPREnabled && this.minimalMode
|
||||
this.isAppPPREnabled && this.minimalMode
|
||||
? new PostponedPathnameNormalizer()
|
||||
: undefined,
|
||||
rsc:
|
||||
|
@ -508,7 +510,7 @@ export default abstract class Server<
|
|||
? new RSCPathnameNormalizer()
|
||||
: undefined,
|
||||
prefetchRSC:
|
||||
isAppPPREnabled && this.minimalMode
|
||||
this.isAppPPREnabled && this.minimalMode
|
||||
? new PrefetchRSCPathnameNormalizer()
|
||||
: undefined,
|
||||
data: this.enabledDirectories.pages
|
||||
|
@ -568,7 +570,6 @@ export default abstract class Server<
|
|||
// @ts-expect-error internal field not publicly exposed
|
||||
isExperimentalCompile: this.nextConfig.experimental.isExperimentalCompile,
|
||||
experimental: {
|
||||
isAppPPREnabled,
|
||||
swrDelta: this.nextConfig.swrDelta,
|
||||
clientTraceMetadata: this.nextConfig.experimental.clientTraceMetadata,
|
||||
after: this.nextConfig.experimental.after ?? false,
|
||||
|
@ -2009,9 +2010,9 @@ export default abstract class Server<
|
|||
* enabled, then the given route _could_ support PPR.
|
||||
*/
|
||||
const couldSupportPPR: boolean =
|
||||
this.isAppPPREnabled &&
|
||||
typeof routeModule !== 'undefined' &&
|
||||
isAppPageRouteModule(routeModule) &&
|
||||
this.renderOpts.experimental.isAppPPREnabled
|
||||
isAppPageRouteModule(routeModule)
|
||||
|
||||
// If this is a request that's rendering an app page that support's PPR,
|
||||
// then if we're in development mode (or using the experimental test
|
||||
|
@ -2772,6 +2773,7 @@ export default abstract class Server<
|
|||
incrementalCache,
|
||||
isOnDemandRevalidate,
|
||||
isPrefetch: req.headers.purpose === 'prefetch',
|
||||
isRoutePPREnabled,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -19,12 +19,6 @@ type FileSystemCacheContext = Omit<
|
|||
> & {
|
||||
fs: CacheFs
|
||||
serverDistDir: string
|
||||
|
||||
/**
|
||||
* isAppPPREnabled is true when PPR has been enabled either globally or just for
|
||||
* some pages via the `incremental` option.
|
||||
*/
|
||||
isAppPPREnabled: boolean
|
||||
}
|
||||
|
||||
type TagsManifest = {
|
||||
|
@ -42,7 +36,6 @@ export default class FileSystemCache implements CacheHandler {
|
|||
private pagesDir: boolean
|
||||
private tagsManifestPath?: string
|
||||
private revalidatedTags: string[]
|
||||
private readonly isAppPPREnabled: boolean
|
||||
private debug: boolean
|
||||
|
||||
constructor(ctx: FileSystemCacheContext) {
|
||||
|
@ -52,7 +45,6 @@ export default class FileSystemCache implements CacheHandler {
|
|||
this.appDir = !!ctx._appDir
|
||||
this.pagesDir = !!ctx._pagesDir
|
||||
this.revalidatedTags = ctx.revalidatedTags
|
||||
this.isAppPPREnabled = ctx.isAppPPREnabled
|
||||
this.debug = !!process.env.NEXT_PRIVATE_DEBUG_CACHE
|
||||
|
||||
if (ctx.maxMemoryCacheSize) {
|
||||
|
@ -177,7 +169,7 @@ export default class FileSystemCache implements CacheHandler {
|
|||
|
||||
public async get(...args: Parameters<CacheHandler['get']>) {
|
||||
const [key, ctx = {}] = args
|
||||
const { tags, softTags, kindHint } = ctx
|
||||
const { tags, softTags, kindHint, isRoutePPREnabled } = ctx
|
||||
let data = memoryCache?.get(key)
|
||||
|
||||
if (this.debug) {
|
||||
|
@ -246,7 +238,10 @@ export default class FileSystemCache implements CacheHandler {
|
|||
if (this.debug) {
|
||||
console.log('tags vs storedTags mismatch', tags, storedTags)
|
||||
}
|
||||
await this.set(key, data.value, { tags })
|
||||
await this.set(key, data.value, {
|
||||
tags,
|
||||
isRoutePPREnabled,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -254,7 +249,7 @@ export default class FileSystemCache implements CacheHandler {
|
|||
? await this.fs.readFile(
|
||||
this.getFilePath(
|
||||
`${key}${
|
||||
this.isAppPPREnabled ? RSC_PREFETCH_SUFFIX : RSC_SUFFIX
|
||||
isRoutePPREnabled ? RSC_PREFETCH_SUFFIX : RSC_SUFFIX
|
||||
}`,
|
||||
'app'
|
||||
),
|
||||
|
@ -398,7 +393,7 @@ export default class FileSystemCache implements CacheHandler {
|
|||
this.getFilePath(
|
||||
`${key}${
|
||||
isAppPath
|
||||
? this.isAppPPREnabled
|
||||
? ctx.isRoutePPREnabled
|
||||
? RSC_PREFETCH_SUFFIX
|
||||
: RSC_SUFFIX
|
||||
: NEXT_DATA_SUFFIX
|
||||
|
|
|
@ -31,7 +31,6 @@ export interface CacheHandlerContext {
|
|||
fetchCacheKeyPrefix?: string
|
||||
prerenderManifest?: PrerenderManifest
|
||||
revalidatedTags: string[]
|
||||
isAppPPREnabled?: boolean
|
||||
_appDir: boolean
|
||||
_pagesDir: boolean
|
||||
_requestHeaders: IncrementalCache['requestHeaders']
|
||||
|
@ -104,7 +103,6 @@ export class IncrementalCache implements IncrementalCacheType {
|
|||
fetchCacheKeyPrefix,
|
||||
CurCacheHandler,
|
||||
allowedRevalidateHeaderKeys,
|
||||
isAppPPREnabled,
|
||||
}: {
|
||||
fs?: CacheFs
|
||||
dev: boolean
|
||||
|
@ -121,7 +119,6 @@ export class IncrementalCache implements IncrementalCacheType {
|
|||
getPrerenderManifest: () => DeepReadonly<PrerenderManifest>
|
||||
fetchCacheKeyPrefix?: string
|
||||
CurCacheHandler?: typeof CacheHandler
|
||||
isAppPPREnabled: boolean
|
||||
}) {
|
||||
const debug = !!process.env.NEXT_PRIVATE_DEBUG_CACHE
|
||||
this.hasCustomCacheHandler = Boolean(CurCacheHandler)
|
||||
|
@ -193,7 +190,6 @@ export class IncrementalCache implements IncrementalCacheType {
|
|||
_appDir: !!appDir,
|
||||
_requestHeaders: requestHeaders,
|
||||
fetchCacheKeyPrefix,
|
||||
isAppPPREnabled,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -434,6 +430,7 @@ export class IncrementalCache implements IncrementalCacheType {
|
|||
fetchIdx?: number
|
||||
tags?: string[]
|
||||
softTags?: string[]
|
||||
isRoutePPREnabled?: boolean
|
||||
} = {}
|
||||
): Promise<IncrementalCacheEntry | null> {
|
||||
if (
|
||||
|
@ -556,6 +553,7 @@ export class IncrementalCache implements IncrementalCacheType {
|
|||
fetchUrl?: string
|
||||
fetchIdx?: number
|
||||
tags?: string[]
|
||||
isRoutePPREnabled?: boolean
|
||||
}
|
||||
) {
|
||||
if (
|
||||
|
|
|
@ -391,7 +391,6 @@ export default class NextNodeServer extends BaseServer<
|
|||
!this.minimalMode && this.nextConfig.experimental.isrFlushToDisk,
|
||||
getPrerenderManifest: () => this.getPrerenderManifest(),
|
||||
CurCacheHandler: CacheHandler,
|
||||
isAppPPREnabled: this.renderOpts.experimental.isAppPPREnabled,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ export default class ResponseCache implements ResponseCacheBase {
|
|||
isOnDemandRevalidate?: boolean
|
||||
isPrefetch?: boolean
|
||||
incrementalCache: IncrementalCache
|
||||
isRoutePPREnabled?: boolean
|
||||
}
|
||||
): Promise<ResponseCacheEntry | null> {
|
||||
// If there is no key for the cache, we can't possibly look this up in the
|
||||
|
@ -89,7 +90,10 @@ export default class ResponseCache implements ResponseCacheBase {
|
|||
let cachedResponse: IncrementalCacheItem = null
|
||||
try {
|
||||
cachedResponse = !this.minimalMode
|
||||
? await incrementalCache.get(key, { kindHint })
|
||||
? await incrementalCache.get(key, {
|
||||
kindHint,
|
||||
isRoutePPREnabled: context.isRoutePPREnabled,
|
||||
})
|
||||
: null
|
||||
|
||||
if (cachedResponse && !isOnDemandRevalidate) {
|
||||
|
@ -153,6 +157,7 @@ export default class ResponseCache implements ResponseCacheBase {
|
|||
} else {
|
||||
await incrementalCache.set(key, resolveValue.value, {
|
||||
revalidate: resolveValue.revalidate,
|
||||
isRoutePPREnabled: context.isRoutePPREnabled,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +172,7 @@ export default class ResponseCache implements ResponseCacheBase {
|
|||
Math.max(cachedResponse.revalidate || 3, 3),
|
||||
30
|
||||
),
|
||||
isRoutePPREnabled: context.isRoutePPREnabled,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ export interface ResponseCacheBase {
|
|||
* provided it will test the filesystem to check.
|
||||
*/
|
||||
routeKind?: RouteKind
|
||||
|
||||
isRoutePPREnabled?: boolean
|
||||
}
|
||||
): Promise<ResponseCacheEntry | null>
|
||||
}
|
||||
|
@ -139,11 +141,16 @@ export interface IncrementalCache {
|
|||
* determine the kind from the filesystem.
|
||||
*/
|
||||
kindHint?: IncrementalCacheKindHint
|
||||
|
||||
isRoutePPREnabled?: boolean
|
||||
}
|
||||
) => Promise<IncrementalCacheItem>
|
||||
set: (
|
||||
key: string,
|
||||
data: IncrementalCacheValue | null,
|
||||
ctx: { revalidate: Revalidate }
|
||||
ctx: {
|
||||
revalidate: Revalidate
|
||||
isRoutePPREnabled?: boolean
|
||||
}
|
||||
) => Promise<void>
|
||||
}
|
||||
|
|
|
@ -93,8 +93,6 @@ export default class NextWebServer extends BaseServer<
|
|||
CurCacheHandler:
|
||||
this.serverOptions.webServerConfig.incrementalCacheHandler,
|
||||
getPrerenderManifest: () => this.getPrerenderManifest(),
|
||||
// PPR is not supported in the Edge runtime.
|
||||
isAppPPREnabled: false,
|
||||
})
|
||||
}
|
||||
protected getResponseCache() {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { TestPage } from '../../../components/page'
|
||||
|
||||
export const experimental_ppr = true
|
||||
|
||||
export default function Page({ params: { locale } }) {
|
||||
return <TestPage pathname={`/${locale}/about`} />
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { locales } from '../../components/page'
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return locales.map((locale) => ({ locale }))
|
||||
}
|
||||
|
||||
export default function Layout({ children, params: { locale } }) {
|
||||
return (
|
||||
<html lang={locale}>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { TestPage } from '../../components/page'
|
||||
|
||||
export default function Page({ params: { locale } }) {
|
||||
return <TestPage pathname={`/${locale}`} />
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { TestPage } from '../../../components/page'
|
||||
|
||||
export default function Page({ params: { locale } }) {
|
||||
return <TestPage pathname={`/${locale}/static`} noDynamic />
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default ({ children }) => {
|
||||
return children
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { redirect } from 'next/navigation'
|
||||
import { locales } from '../components/page'
|
||||
|
||||
export default () => {
|
||||
// Redirect to the default locale
|
||||
return redirect(`/${locales[0]}`)
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import { unstable_noStore } from 'next/cache'
|
||||
import Link from 'next/link'
|
||||
import { Suspense } from 'react'
|
||||
|
||||
export const locales = ['en', 'fr']
|
||||
|
||||
export const links = [
|
||||
{ href: '/', text: 'Home' },
|
||||
...locales
|
||||
.map((locale) => {
|
||||
return [
|
||||
{ href: `/${locale}`, text: locale },
|
||||
{ href: `/${locale}/about`, text: `${locale} - About` },
|
||||
{ href: `/${locale}/static`, text: `${locale} - Static` },
|
||||
]
|
||||
})
|
||||
.flat(),
|
||||
]
|
||||
|
||||
function Dynamic({ noDynamic = false }) {
|
||||
if (!noDynamic) unstable_noStore()
|
||||
return <div id="dynamic">Dynamic</div>
|
||||
}
|
||||
|
||||
export function TestPage({ pathname, noDynamic = false }) {
|
||||
return (
|
||||
<div>
|
||||
<ul>
|
||||
{links.map(({ href, text }) => (
|
||||
<li key={href}>
|
||||
<Link href={href}>{text}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<code data-value={pathname}>{pathname}</code>
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Dynamic noDynamic={noDynamic} />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
import { NextInstance, nextTestSetup } from 'e2e-utils'
|
||||
import { links, locales } from './components/page'
|
||||
import glob from 'glob'
|
||||
import { promisify } from 'node:util'
|
||||
|
||||
const globp = promisify(glob)
|
||||
|
||||
async function getDotNextFiles(next: NextInstance): Promise<Array<string>> {
|
||||
const files = await globp('**/.next/**/*', {
|
||||
cwd: next.testDir,
|
||||
absolute: true,
|
||||
})
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
describe('ppr-navigations incremental', () => {
|
||||
const { next, isNextDev, isTurbopack } = nextTestSetup({
|
||||
files: __dirname,
|
||||
})
|
||||
|
||||
it('can navigate between all the links and back without writing to disk', async () => {
|
||||
const before = !isNextDev && !isTurbopack ? await getDotNextFiles(next) : []
|
||||
|
||||
const browser = await next.browser('/')
|
||||
|
||||
// Add a variable to the window so we can tell if it MPA navigated. If this
|
||||
// value is still true at the end of the test, then we know that the page
|
||||
// didn't MPA navigate.
|
||||
const random = Math.random().toString(36).substring(7)
|
||||
await browser.eval(`window.random = ${JSON.stringify(random)}`)
|
||||
|
||||
try {
|
||||
for (const { href } of links) {
|
||||
// Find the link element for the href and click it.
|
||||
await browser.elementByCss(`a[href="${href}"]`).click()
|
||||
|
||||
// Wait for the network to be idle. This seems odd, but this is to help
|
||||
// catch the condition where a rouge 404 triggers a MPA navigation.
|
||||
await browser.waitForIdleNetwork()
|
||||
|
||||
// Check if the page navigated.
|
||||
expect(await browser.eval(`window.random`)).toBe(random)
|
||||
|
||||
// Wait for that page to load.
|
||||
if (href === '/') {
|
||||
// The root page redirects to the first locale.
|
||||
await browser.waitForElementByCss(`[data-value="/${locales[0]}"]`)
|
||||
} else {
|
||||
await browser.waitForElementByCss(`[data-value="${href}"]`)
|
||||
}
|
||||
|
||||
await browser.elementByCss('#dynamic')
|
||||
}
|
||||
} finally {
|
||||
await browser.close()
|
||||
}
|
||||
|
||||
if (!isNextDev && !isTurbopack) {
|
||||
const after = await getDotNextFiles(next)
|
||||
|
||||
// Ensure that no new files were written to disk. If this test fails, it's
|
||||
// likely that there was a change to the incremental cache or file system
|
||||
// cache that resulted in information like the ppr state not being properly
|
||||
// propagated.
|
||||
expect(after).toEqual(before)
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
experimental: {
|
||||
ppr: 'incremental',
|
||||
},
|
||||
}
|
|
@ -15,7 +15,6 @@ describe('FileSystemCache', () => {
|
|||
fs: nodeFs,
|
||||
serverDistDir: cacheDir,
|
||||
revalidatedTags: [],
|
||||
isAppPPREnabled: false,
|
||||
})
|
||||
|
||||
const binary = await fs.readFile(
|
||||
|
@ -55,7 +54,6 @@ describe('FileSystemCache (isrMemory 0)', () => {
|
|||
fs: nodeFs,
|
||||
serverDistDir: cacheDir,
|
||||
revalidatedTags: [],
|
||||
isAppPPREnabled: false,
|
||||
maxMemoryCacheSize: 0, // disable memory cache
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue