mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
### What? This PR fixes an issue where pages with fallback route params weren't triggering dynamic resume behavior in PPR (Partial Pre-Rendering). ### Why? When fallback route params exist, the RSC (React Server Components) data is inherently dynamic because the params are encoded into the flight router state. Without this fix, pages with fallback route params would incorrectly be treated as fully static, leading to incorrect behavior. ### How? - Added a check in `app-render.tsx` to ensure that pages with fallback route params (`workStore.fallbackRouteParams.size > 0`) always perform a dynamic resume after the static prerender - Refactored PPR tests to use deterministic sentinel markers (`<\!-- PPR_BOUNDARY_SENTINEL -->`) instead of time-based measurements for more reliable testing - Updated the test utilities to split responses based on the sentinel marker rather than timing delays This ensures that: 1. Pages with fallback route params correctly trigger dynamic behavior 2. PPR tests are more reliable and deterministic 3. The boundary between static and dynamic content is clearly marked in test mode Fixes #
43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
/**
|
|
* Measures and separates static and dynamic content in a response stream
|
|
* by splitting on PPR boundary sentinel markers.
|
|
*
|
|
* This function is used in Partial Prerendering (PPR) tests to analyze the output
|
|
* of Next.js pages and verify that static and dynamic content are properly separated.
|
|
*
|
|
* @param fn - A function that returns a Promise resolving to a readable stream
|
|
* containing HTML with PPR boundary markers
|
|
* @returns An object containing the separated static and dynamic chunks
|
|
*
|
|
* @example
|
|
* const [staticPart, dynamicPart] = await splitResponseWithPPRSentinel(async () => {
|
|
* return fetch('/some-ppr-page').then(res => res.body)
|
|
* })
|
|
* console.log(staticPart) // Content before the boundary
|
|
* console.log(dynamicPart) // Content after the boundary
|
|
*/
|
|
export async function splitResponseWithPPRSentinel(
|
|
fn: () => Promise<NodeJS.ReadableStream>
|
|
): Promise<[staticPart: string, dynamicPart: string]> {
|
|
const stream = await fn()
|
|
const chunks: string[] = []
|
|
|
|
await new Promise<void>((resolve, reject) => {
|
|
stream.on('data', (chunk: Buffer | string) => {
|
|
if (typeof chunk !== 'string') {
|
|
chunk = chunk.toString('utf8')
|
|
}
|
|
|
|
chunks.push(chunk)
|
|
})
|
|
|
|
stream.on('end', resolve)
|
|
stream.on('error', reject)
|
|
})
|
|
|
|
// Combine all chunks and split on the PPR boundary sentinel
|
|
// The sentinel marks the boundary between static and dynamic content
|
|
const parts = chunks.join('').split('<!-- PPR_BOUNDARY_SENTINEL -->', 2)
|
|
return [parts[0] ?? '', parts[1] ?? '']
|
|
}
|