diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 33fb8096b617b..a4c8095cab7ef 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -165,6 +165,7 @@ import { getRevalidateReason } from './instrumentation/utils' import { RouteKind } from './route-kind' import type { RouteModule } from './route-modules/route-module' import { FallbackMode, parseFallbackField } from '../lib/fallback' +import { toResponseCacheEntry } from './response-cache/utils' export type FindComponentsResult = { components: LoadComponentsReturnType @@ -2335,17 +2336,12 @@ export default abstract class Server< * a render that has been postponed. */ postponed: string | undefined - - /** - * Whether or not this render is a fallback render. - */ - isFallback: boolean | undefined } type Renderer = ( context: RendererContext ) => Promise - const doRender: Renderer = async ({ postponed, isFallback }) => { + const doRender: Renderer = async ({ postponed }) => { // In development, we always want to generate dynamic HTML. let supportsDynamicResponse: boolean = // If we're in development, we always support dynamic HTML, unless it's @@ -2510,7 +2506,6 @@ export default abstract class Server< body: Buffer.from(await blob.arrayBuffer()), headers, }, - isFallback: false, revalidate, } @@ -2668,11 +2663,7 @@ export default abstract class Server< // Handle `isNotFound`. if ('isNotFound' in metadata && metadata.isNotFound) { - return { - value: null, - revalidate: metadata.revalidate, - isFallback: false, - } + return { value: null, revalidate: metadata.revalidate } } // Handle `isRedirect`. @@ -2683,7 +2674,6 @@ export default abstract class Server< props: metadata.pageData ?? metadata.flightData, } satisfies CachedRedirectValue, revalidate: metadata.revalidate, - isFallback: false, } } @@ -2704,7 +2694,6 @@ export default abstract class Server< status: res.statusCode, } satisfies CachedAppPageValue, revalidate: metadata.revalidate, - isFallback, } } @@ -2717,7 +2706,6 @@ export default abstract class Server< status: isAppPath ? res.statusCode : undefined, } satisfies CachedPageValue, revalidate: metadata.revalidate, - isFallback, } } @@ -2844,16 +2832,26 @@ export default abstract class Server< : pathname : null - return this.responseCache.get( + const fallbackResponse = await this.responseCache.get( key, - async () => { + async ({ previousCacheEntry: previousFallbackCacheEntry }) => { + // For the pages router, fallbacks cannot be revalidated or + // generated in production. In the case of a missing fallback, + // we return null, but if it's being revalidated, we just return + // the previous fallback cache entry. This preserves the previous + // behavior. + if (isProduction) { + if (!previousFallbackCacheEntry) { + return null + } + + return toResponseCacheEntry(previousFallbackCacheEntry) + } + query.__nextFallback = 'true' - return doRender({ - // We pass `undefined` as rendering a fallback isn't resumed here. - postponed: undefined, - isFallback: true, - }) + // We pass `undefined` as rendering a fallback isn't resumed here. + return doRender({ postponed: undefined }) }, { routeKind: isAppPath ? RouteKind.APP_PAGE : RouteKind.PAGES, @@ -2862,6 +2860,14 @@ export default abstract class Server< isFallback: true, } ) + + if (!fallbackResponse) return null + + // Remove the revalidate from the response to prevent it from being + // used in the surrounding cache. + delete fallbackResponse.revalidate + + return fallbackResponse } } @@ -2872,7 +2878,6 @@ export default abstract class Server< !isOnDemandRevalidate && !isRevalidating && minimalPostponed ? minimalPostponed : undefined, - isFallback: false, } // When we're in minimal mode, if we're trying to debug the static shell, @@ -2883,7 +2888,6 @@ export default abstract class Server< ) { return { revalidate: 1, - isFallback: false, value: { kind: CachedRouteKind.PAGES, html: RenderResult.fromStatic(''), @@ -3263,10 +3267,7 @@ export default abstract class Server< // Perform the render again, but this time, provide the postponed state. // We don't await because we want the result to start streaming now, and // we've already chained the transformer's readable to the render result. - doRender({ - postponed: cachedData.postponed, - isFallback: false, - }) + doRender({ postponed: cachedData.postponed }) .then(async (result) => { if (!result) { throw new Error('Invariant: expected a result to be returned') diff --git a/packages/next/src/server/image-optimizer.ts b/packages/next/src/server/image-optimizer.ts index 29bb2a824ae56..34127d24532b7 100644 --- a/packages/next/src/server/image-optimizer.ts +++ b/packages/next/src/server/image-optimizer.ts @@ -368,7 +368,6 @@ export class ImageOptimizerCache { revalidateAfter: Math.max(maxAge, this.nextConfig.images.minimumCacheTTL) * 1000 + Date.now(), - isFallback: false, curRevalidate: maxAge, isStale: now > expireAt, } diff --git a/packages/next/src/server/lib/incremental-cache/index.ts b/packages/next/src/server/lib/incremental-cache/index.ts index 10601447a0e0a..96bb96dc75ad2 100644 --- a/packages/next/src/server/lib/incremental-cache/index.ts +++ b/packages/next/src/server/lib/incremental-cache/index.ts @@ -427,7 +427,6 @@ export class IncrementalCache implements IncrementalCacheType { return { isStale: isStale, - isFallback: false, value: { kind: CachedRouteKind.FETCH, data, @@ -464,7 +463,6 @@ export class IncrementalCache implements IncrementalCacheType { curRevalidate, revalidateAfter, value: cacheData.value, - isFallback: ctx.isFallback, } } @@ -482,7 +480,6 @@ export class IncrementalCache implements IncrementalCacheType { value: null, curRevalidate, revalidateAfter, - isFallback: ctx.isFallback, } this.set(cacheKey, entry.value, ctx) } diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 02ea633ae52ff..4f72b162868f0 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -872,7 +872,6 @@ export default class NextNodeServer extends BaseServer< etag, extension: getExtension(contentType) as string, }, - isFallback: false, revalidate: maxAge, } }, diff --git a/packages/next/src/server/response-cache/index.ts b/packages/next/src/server/response-cache/index.ts index e989c4a3c5c14..844e485532317 100644 --- a/packages/next/src/server/response-cache/index.ts +++ b/packages/next/src/server/response-cache/index.ts @@ -101,11 +101,6 @@ export default class ResponseCache implements ResponseCacheBase { }) : null - // Ensure that cached responses that are fallbacks are marked as such. - if (cachedResponse) { - cachedResponse.isFallback = isFallback - } - if (cachedResponse && !isOnDemandRevalidate) { if (cachedResponse.value?.kind === CachedRouteKind.FETCH) { throw new Error( @@ -158,13 +153,8 @@ export default class ResponseCache implements ResponseCacheBase { } // We want to persist the result only if it has a revalidate value - // defined and it's not the fallback result. The fallback result has - // it's own wrapping cache. - if ( - typeof resolveValue.revalidate !== 'undefined' && - (!resolveValue.isFallback || - (resolveValue.isFallback && isFallback)) - ) { + // defined. + if (typeof resolveValue.revalidate !== 'undefined') { if (this.minimalMode) { this.previousCacheItem = { key: cacheKey, diff --git a/packages/next/src/server/response-cache/types.ts b/packages/next/src/server/response-cache/types.ts index eef8c6dfdd139..3a8f1ff329e3b 100644 --- a/packages/next/src/server/response-cache/types.ts +++ b/packages/next/src/server/response-cache/types.ts @@ -134,7 +134,6 @@ export type IncrementalCacheEntry = { revalidateAfter: Revalidate // -1 here dictates a blocking revalidate should be used isStale?: boolean | -1 - isFallback: boolean | undefined value: IncrementalCacheValue | null } @@ -158,7 +157,6 @@ export type ResponseCacheEntry = { value: ResponseCacheValue | null isStale?: boolean | -1 isMiss?: boolean - isFallback: boolean | undefined } /** @@ -178,7 +176,6 @@ export type IncrementalCacheItem = { value: IncrementalCacheValue | null isStale?: boolean | -1 isMiss?: boolean - isFallback?: boolean } | null export const enum IncrementalCacheKind { diff --git a/packages/next/src/server/response-cache/utils.ts b/packages/next/src/server/response-cache/utils.ts index f7424bfbf2b17..ca8a8e647b714 100644 --- a/packages/next/src/server/response-cache/utils.ts +++ b/packages/next/src/server/response-cache/utils.ts @@ -51,7 +51,6 @@ export async function toResponseCacheEntry( return { isMiss: response.isMiss, isStale: response.isStale, - isFallback: response.isFallback, revalidate: response.revalidate, value: response.value?.kind === CachedRouteKind.PAGES