mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
A new `GenerateStaticParamsStore` work unit store type is now provided during `generateStaticParams` execution. This enables root param getters (`import { lang } from 'next/root-params'`) to be called inside `generateStaticParams`, allowing shared helpers that internally access root params via the special import to be used in both Server Components and `generateStaticParams` without manually threading params.
Each `generateStaticParams` call now runs within a `workUnitAsyncStorage.run()` context carrying a `GenerateStaticParamsStore` with the correct `rootParams` (extracted from `parentParams` using the already-available `rootParamKeys`). The store extends `CommonWorkUnitStore`, providing `phase` and `implicitTags` which are not strictly necessary but convenient to keep call sites simple.
Request-time APIs (`headers()`, `cookies()`, `connection()`, `draftMode()`) now throw specific errors when called inside `generateStaticParams` instead of the previous generic "called outside a request scope" message. Framework-internal functions like `createSearchParamsFromClient` and `createParamsFromClient` throw `InvariantError` since they should never be reached in this context.
This change also unblocks a follow-up PR that removes `| undefined` from `PublicCacheContext.outerWorkUnitStore` in the use cache wrapper, since `"use cache"` is already supported inside `generateStaticParams` today but previously ran without a `WorkUnitStore`. With this store in place, requiring a `WorkUnitStore` in `"use cache"` won't break that existing usage.
55 lines
2.5 KiB
TypeScript
55 lines
2.5 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
|
|
describe('generate-static-params-errors', () => {
|
|
const { next } = nextTestSetup({
|
|
files: __dirname,
|
|
skipStart: true,
|
|
})
|
|
|
|
let cliOutputLength: number
|
|
|
|
afterEach(async () => {
|
|
await next.stop()
|
|
})
|
|
|
|
const buildRoute = async (routePath: string) => {
|
|
cliOutputLength = next.cliOutput.length
|
|
await next.build({ args: ['--debug-build-paths', routePath] })
|
|
}
|
|
|
|
const getCliOutput = () => next.cliOutput.slice(cliOutputLength)
|
|
|
|
it('should error when cookies() is called inside generateStaticParams', async () => {
|
|
await buildRoute('app/[lang]/cookies/[slug]/page.tsx')
|
|
expect(getCliOutput()).toContain(
|
|
'Error: Route /[lang]/cookies/[slug] used `cookies()` inside `generateStaticParams`. This is not supported because `generateStaticParams` runs at build time without an HTTP request. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context'
|
|
)
|
|
})
|
|
|
|
it('should error when headers() is called inside generateStaticParams', async () => {
|
|
await buildRoute('app/[lang]/headers/[slug]/page.tsx')
|
|
expect(getCliOutput()).toContain(
|
|
'Error: Route /[lang]/headers/[slug] used `headers()` inside `generateStaticParams`. This is not supported because `generateStaticParams` runs at build time without an HTTP request. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context'
|
|
)
|
|
})
|
|
|
|
it('should error when connection() is called inside generateStaticParams', async () => {
|
|
await buildRoute('app/[lang]/connection/[slug]/page.tsx')
|
|
expect(getCliOutput()).toContain(
|
|
'Error: Route /[lang]/connection/[slug] used `connection()` inside `generateStaticParams`. This is not supported because `generateStaticParams` runs at build time without an HTTP request. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context'
|
|
)
|
|
})
|
|
|
|
it('should error when draftMode() is called inside generateStaticParams', async () => {
|
|
await buildRoute('app/[lang]/draft-mode/[slug]/page.tsx')
|
|
expect(getCliOutput()).toContain(
|
|
'Error: Route /[lang]/draft-mode/[slug] used `draftMode()` inside `generateStaticParams`. This is not supported because `generateStaticParams` runs at build time without an HTTP request. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context'
|
|
)
|
|
})
|
|
|
|
it('should allow root params access inside generateStaticParams', async () => {
|
|
await buildRoute('app/[lang]/root-params/[slug]/page.tsx')
|
|
expect(getCliOutput()).not.toContain('Error')
|
|
})
|
|
})
|