Skip to content

Commit

Permalink
Add fallbackExpire to prerender manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
unstubbable committed Feb 21, 2025
1 parent daf02c4 commit aae5319
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 23 deletions.
20 changes: 14 additions & 6 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ export interface DynamicPrerenderManifestRoute {
*/
fallbackRevalidate: Revalidate | undefined

/**
* When defined, it describes the expire configuration for the fallback route.
*/
fallbackExpire: Revalidate | undefined

/**
* The headers that should used when serving the fallback.
*/
Expand Down Expand Up @@ -3037,12 +3042,13 @@ export default async function build(
const fallbackMode =
route.fallbackMode ?? FallbackMode.NOT_FOUND

// When we're configured to serve a prerender, we should use the
// fallback revalidate from the export result. If it can't be
// found, mark that we should keep the shell forever (`false`).
let fallbackRevalidate: Revalidate | undefined =
// When the route is configured to serve a prerender, we should
// use the cache control from the export result. If it can't be
// found, mark that we should keep the shell forever
// (revalidate: `false` via `getCacheControl()`).
const fallbackCacheControl =
isRoutePPREnabled && fallbackMode === FallbackMode.PRERENDER
? cacheControl.revalidate
? cacheControl
: undefined

const fallback: Fallback = fallbackModeToFallbackField(
Expand Down Expand Up @@ -3072,7 +3078,8 @@ export default async function build(
),
dataRoute,
fallback,
fallbackRevalidate,
fallbackRevalidate: fallbackCacheControl?.revalidate,
fallbackExpire: fallbackCacheControl?.expire,
fallbackStatus: meta.status,
fallbackHeaders: meta.headers,
fallbackRootParams: route.fallbackRootParams,
Expand Down Expand Up @@ -3521,6 +3528,7 @@ export default async function build(
? `${normalizedRoute}.html`
: false,
fallbackRevalidate: undefined,
fallbackExpire: undefined,
fallbackSourceRoute: undefined,
fallbackRootParams: undefined,
dataRouteRegex: normalizeRouteRegex(
Expand Down
7 changes: 6 additions & 1 deletion test/e2e/app-dir/use-cache/app/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { unstable_cacheLife } from 'next/cache'

async function getCachedRandom(n: number) {
'use cache'
unstable_cacheLife('weeks')
return String(Math.ceil(Math.random() * n))
}

Expand All @@ -11,5 +14,7 @@ export async function generateStaticParams() {
}

export default async function Page() {
return 'hit'
const value = getCachedRandom(1)

return <p>{value}</p>
}
32 changes: 16 additions & 16 deletions test/e2e/app-dir/use-cache/use-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
createRenderResumeDataCache,
RenderResumeDataCache,
} from 'next/dist/server/resume-data-cache/resume-data-cache'
import { PrerenderManifest } from 'next/dist/build'

const GENERIC_RSC_ERROR =
'An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.'
Expand Down Expand Up @@ -371,29 +372,28 @@ describe('use-cache', () => {
})

it('should match the expected revalidate and expire configs on the prerender manifest', async () => {
const prerenderManifest = JSON.parse(
const { version, routes, dynamicRoutes } = JSON.parse(
await next.readFile('.next/prerender-manifest.json')
)
) as PrerenderManifest

expect(prerenderManifest.version).toBe(4)
expect(version).toBe(4)

expect(
prerenderManifest.routes['/cache-life'].initialRevalidateSeconds
).toBe(100)

expect(prerenderManifest.routes['/cache-life'].initialExpireSeconds).toBe(
250
)
// custom cache life profile "frequent"
expect(routes['/cache-life'].initialRevalidateSeconds).toBe(100)
expect(routes['/cache-life'].initialExpireSeconds).toBe(250)

expect(
prerenderManifest.routes['/cache-fetch'].initialExpireSeconds
).toBe(31536000) // default expireTime
// default expireTime
expect(routes['/cache-fetch'].initialExpireSeconds).toBe(31536000)

// The revalidate config from the fetch call should lower the revalidate
// config for the page.
expect(
prerenderManifest.routes['/cache-tag'].initialRevalidateSeconds
).toBe(42)
expect(routes['/cache-tag'].initialRevalidateSeconds).toBe(42)

if (process.env.__NEXT_EXPERIMENTAL_PPR === 'true') {
// cache life profile "weeks"
expect(dynamicRoutes['/[id]'].fallbackRevalidate).toBe(604800)
expect(dynamicRoutes['/[id]'].fallbackExpire).toBe(2592000)
}
})

it('should match the expected stale config in the page header', async () => {
Expand Down

0 comments on commit aae5319

Please sign in to comment.