fef6f82aba
When using imports from `next/headers` in a layout or page, `StaticGenerationBailout` will throw an error to indicate Next.js should fallback to dynamic rendering. However, when async context is lost, this error is uncaught and leads to a confusing error message at build time. This attempts to improve DX surrounding this error by linking out to a page that explains when it might happen. I've also tweaked `StaticGenerationBailout` to always throw a fully descriptive reason as opposed to just `DynamicServerError: Dynamic server usage: cookies` Closes NEXT-1181 Fixes #49373 --------- Co-authored-by: Lee Robinson <me@leerob.io> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
71 lines
2 KiB
TypeScript
71 lines
2 KiB
TypeScript
import { createNextDescribe } from '../../../lib/e2e-utils'
|
|
import { outdent } from 'outdent'
|
|
|
|
createNextDescribe(
|
|
'headers-static-bailout',
|
|
{
|
|
files: __dirname,
|
|
dependencies: {
|
|
nanoid: '4.0.1',
|
|
},
|
|
},
|
|
({ next, isNextStart }) => {
|
|
if (!isNextStart) {
|
|
it('should skip', () => {})
|
|
return
|
|
}
|
|
|
|
it('should bailout when using an import from next/headers', async () => {
|
|
const url = '/page-with-headers'
|
|
const $ = await next.render$(url)
|
|
expect($('h1').text()).toBe('Dynamic Page')
|
|
|
|
// Check if the page is not statically generated.
|
|
const id = $('#nanoid').text()
|
|
const $2 = await next.render$(url)
|
|
const id2 = $2('#nanoid').text()
|
|
expect(id).not.toBe(id2)
|
|
})
|
|
|
|
it('should not bailout when not using headers', async () => {
|
|
const url = '/page-without-headers'
|
|
|
|
const $ = await next.render$(url)
|
|
expect($('h1').text()).toBe('Static Page')
|
|
|
|
// Check if the page is not statically generated.
|
|
const id = $('#nanoid').text()
|
|
const $2 = await next.render$(url)
|
|
const id2 = $2('#nanoid').text()
|
|
expect(id).toBe(id2)
|
|
})
|
|
|
|
it('it provides a helpful link in case static generation bailout is uncaught', async () => {
|
|
await next.stop()
|
|
await next.patchFile(
|
|
'app/server-components-page/page.tsx',
|
|
outdent`
|
|
import { cookies } from 'next/headers'
|
|
|
|
async function foo() {
|
|
return new Promise((resolve) =>
|
|
// break out of the expected async context, causing an uncaught build-time error
|
|
setTimeout(() => {
|
|
resolve(cookies().getAll())
|
|
}, 1000)
|
|
)
|
|
}
|
|
|
|
export default async function Page() {
|
|
await foo()
|
|
return <div>Hello World</div>
|
|
}
|
|
`
|
|
)
|
|
const { cliOutput } = await next.build()
|
|
expect(cliOutput).toContain(
|
|
'https://nextjs.org/docs/messages/dynamic-server-error'
|
|
)
|
|
})
|
|
}
|
|
)
|