mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
Supersedes https://github.com/vercel/next.js/pull/93475 ## Summary There's a few fixes bundled in here. We're fixing `Infinity` getting serialized to `null`, which caused cache handlers and build workers to misinterpret it as "don't cache" instead of "cache forever". We use the existing infinity sentinel for that. We're also making the checks a bit more specific from `typeof !== 'number'` to forbidding `NaN` and `-Infinity`. The checks are applied consistently for profiles, inline cache life, and arguments to `fetch` and `unstable_cache`. Now that configs are also validated, we need to make sure that we only do `revalidate > expire` validation when both values are specified. There's a regression test for that, which https://github.com/vercel/next.js/pull/93475 didn't do correctly. Also, per review below: - Now actually using returned value for `unstable_cache` - Added validation + infinity fix for `revalidateTag` profile - Added validation + infinity fix in `config.experimental.staleTimes` and `config.expireTime` - Added deep clone for `defaultConfig.cacheLife` ## Test Plan New e2e tests that fail before the fixes. --------- Co-authored-by: Zack Tanner <[email protected]>
42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
|
|
const uuidRegExp =
|
|
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/
|
|
|
|
describe('use-cache-infinity-profile', () => {
|
|
const { next, isNextStart } = nextTestSetup({
|
|
files: __dirname,
|
|
// Deployment platforms provide their own cache handlers.
|
|
skipDeployment: true,
|
|
})
|
|
|
|
it('caches forever with a configured profile using Infinity revalidate and expire', async () => {
|
|
const $ = await next.render$('/')
|
|
const initialValue = $('#value').text()
|
|
expect(initialValue).toMatch(uuidRegExp)
|
|
|
|
// An infinite cache life must not degrade into a dynamic cache life, so
|
|
// the value stays the same across requests instead of regenerating.
|
|
const $second = await next.render$('/')
|
|
expect($second('#value').text()).toBe(initialValue)
|
|
|
|
if (isNextStart) {
|
|
// The page must be fully prerendered at build time.
|
|
const prerendered = await next.readFile('.next/server/app/index.html')
|
|
expect(prerendered).toContain(initialValue)
|
|
}
|
|
})
|
|
|
|
it('serves an inline Infinity cache life from a JSON-backed cache handler across requests', async () => {
|
|
const $ = await next.render$('/inline?key=a')
|
|
const initialValue = $('#value').text()
|
|
expect(initialValue).toMatch(uuidRegExp)
|
|
|
|
// The second request reads the entry back from the cache handler. If the
|
|
// infinite cache life doesn't survive the handler's JSON round trip, the
|
|
// entry is treated as immediately expired and the value regenerates.
|
|
const $second = await next.render$('/inline?key=a')
|
|
expect($second('#value').text()).toBe(initialValue)
|
|
})
|
|
})
|