mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
### What? This PR wires custom `cacheHandler` / `cacheHandlers` through the remaining edge entrypoints so edge app pages, edge app routes, edge pages SSR, middleware, and edge API routes can all see the configured handlers. It also adds an e2e regression suite covering: - pages-router ISR revalidation with a custom incremental cache handler - app-router cache handlers with cache components enabled - edge app page + edge app route wiring when cache components are disabled ### Why? We already support custom cache handlers in non-edge paths, but several edge code paths were not forwarding that configuration into the generated entrypoints/runtime wrappers. That meant custom cache handlers could be skipped in edge rendering and edge route execution, and we did not have regression coverage around those cases. ### How? - pass `cacheHandler` / `cacheHandlers` through the JS build entry plumbing for edge server entries - inject cache handler imports/registration into the webpack edge templates and loaders - mirror the same wiring in the Turbopack/Rust entry generation for edge app pages, app routes, pages SSR, and middleware - update the edge route wrapper to initialize and register cache handlers before invoking the route module - extend `next-taskless` template expansion with raw injection support so the generated edge templates can add imports and registration code - add `test/e2e/cache-handlers-upstream-wiring` fixtures to cover pages/app, edge/non-edge, and revalidation behavior
138 lines
4.3 KiB
TypeScript
138 lines
4.3 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
import { retry } from 'next-test-utils'
|
|
import { join } from 'path'
|
|
|
|
describe('cache-handlers-upstream-wiring', () => {
|
|
describe('pages router non-edge', () => {
|
|
const { next, skipped, isNextDev } = nextTestSetup({
|
|
files: join(__dirname, 'fixtures/pages-router-non-edge'),
|
|
skipDeployment: true,
|
|
})
|
|
|
|
if (skipped) {
|
|
return
|
|
}
|
|
|
|
let outputIndex = 0
|
|
|
|
beforeEach(() => {
|
|
outputIndex = next.cliOutput.length
|
|
})
|
|
|
|
it('wires res.revalidate() through the configured custom cacheHandler', async () => {
|
|
const initialHtml = await next.render$('/isr')
|
|
const initialValue = initialHtml('#now').text()
|
|
outputIndex = next.cliOutput.length
|
|
|
|
const revalidateResponse = await next.fetch('/api/revalidate')
|
|
expect(revalidateResponse.status).toBe(200)
|
|
expect(await revalidateResponse.json()).toEqual({ revalidated: true })
|
|
|
|
if (!isNextDev) {
|
|
await retry(async () => {
|
|
const htmlAfterRevalidate = await next.render$('/isr')
|
|
const valueAfterRevalidate = htmlAfterRevalidate('#now').text()
|
|
expect(valueAfterRevalidate).not.toBe(initialValue)
|
|
})
|
|
}
|
|
|
|
await next.render$('/isr')
|
|
|
|
await retry(async () => {
|
|
const output = next.cliOutput.slice(outputIndex)
|
|
const constructorLogs =
|
|
output.match(/WiringPagesIncrementalCacheHandler::constructor/g) ?? []
|
|
const sawRevalidateTag = output.includes(
|
|
'WiringPagesIncrementalCacheHandler::revalidateTag'
|
|
)
|
|
|
|
expect(sawRevalidateTag || constructorLogs.length > 0).toBe(true)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('cacheComponents enabled, non-edge app router', () => {
|
|
const { next, skipped, isNextDev } = nextTestSetup({
|
|
files: join(__dirname, 'fixtures/non-edge-cache-components'),
|
|
skipDeployment: true,
|
|
})
|
|
|
|
if (skipped) {
|
|
return
|
|
}
|
|
|
|
let outputIndex = 0
|
|
|
|
beforeEach(() => {
|
|
outputIndex = next.cliOutput.length
|
|
})
|
|
|
|
it('uses configured cacheHandlers for custom app-router cache kind', async () => {
|
|
const pageResponse = await next.fetch('/')
|
|
expect(pageResponse.status).toBe(200)
|
|
|
|
await retry(async () => {
|
|
const output = isNextDev
|
|
? next.cliOutput.slice(outputIndex)
|
|
: next.cliOutput
|
|
expect(output).toContain('WiringModernCacheHandler::set')
|
|
expect(output).toContain('WiringModernCacheHandler::get')
|
|
})
|
|
})
|
|
|
|
it('wires revalidateTag and revalidatePath to the custom cache handler', async () => {
|
|
const seedResponse = await next.fetch('/revalidate-target')
|
|
expect(seedResponse.status).toBe(200)
|
|
|
|
const browser = await next.browser('/revalidate-actions')
|
|
await browser.elementById('revalidate-tag').click()
|
|
await browser.elementById('revalidate-path').click()
|
|
|
|
await retry(async () => {
|
|
const output = next.cliOutput.slice(outputIndex)
|
|
const updateTagLogs =
|
|
output.match(/WiringModernCacheHandler::updateTags/g) ?? []
|
|
|
|
expect(updateTagLogs.length).toBeGreaterThanOrEqual(2)
|
|
expect(output).toContain('custom-tag')
|
|
})
|
|
})
|
|
})
|
|
;(process.env.__NEXT_CACHE_COMPONENTS ? describe.skip : describe)(
|
|
'cacheComponents disabled, edge app router',
|
|
() => {
|
|
const { next, skipped } = nextTestSetup({
|
|
files: join(__dirname, 'fixtures/edge-without-cache-components'),
|
|
skipDeployment: true,
|
|
})
|
|
|
|
if (skipped) {
|
|
return
|
|
}
|
|
|
|
let outputIndex = 0
|
|
|
|
beforeEach(() => {
|
|
outputIndex = next.cliOutput.length
|
|
})
|
|
|
|
it('uses configured cacheHandler for edge app page and edge app route', async () => {
|
|
const edgePageResponse = await next.fetch('/edge-page')
|
|
expect(edgePageResponse.status).toBe(200)
|
|
|
|
const edgeRouteResponse = await next.fetch('/api/edge-route')
|
|
expect(edgeRouteResponse.status).toBe(200)
|
|
expect(await edgeRouteResponse.json()).toEqual({ ok: true })
|
|
|
|
await retry(async () => {
|
|
const output = next.cliOutput.slice(outputIndex)
|
|
const constructorLogs =
|
|
output.match(/WiringIncrementalCacheHandler::constructor/g) ?? []
|
|
|
|
expect(constructorLogs.length).toBeGreaterThanOrEqual(2)
|
|
})
|
|
})
|
|
}
|
|
)
|
|
})
|