Files
Andrew ClarkandGitHub 27e225f468 Fix metadata title dropped on soft navigation with Cache Components (#95315)
With `cacheComponents` + `partialPrefetching`, navigating to an
already-prefetched route with a dynamic `generateMetadata` left
`document.title` permanently empty until a hard reload.

The prefetch cached the head as complete using the server's
`isHeadPartial` flag, which is unreliable under Cache Components. Derive
the head's partiality from `isResponsePartial` instead, as segment data
already does, so a dynamic head is fetched and applied on navigation
while a fully static head stays complete.

Fixing the flag exposed a latent issue in the prefetch scheduler: during
a speculative prefetch, the head was unconditionally runtime-prefetched,
which previously went unnoticed because the head was mismarked as
complete. The head is now runtime-prefetched only when a segment in the
new part of the tree is a candidate for runtime prefetching — it rides
along with that request rather than spawning a standalone one. If
nothing in the new part of the tree is a runtime prefetch candidate, the
head is fetched during the navigation instead. This makes the
scheduler's metadata-only request path dead code, so it's removed.

Fixes #95268.

<!-- NEXT_JS_LLM_PR -->
2026-07-02 08:16:45 -04:00

26 lines
674 B
TypeScript

import type { Metadata } from 'next'
import { connection } from 'next/server'
import { Suspense } from 'react'
// Dynamic metadata: it reads request-time data (`connection()`), so it is not
// part of the prefetchable App Shell and must be fetched on navigation.
export async function generateMetadata(): Promise<Metadata> {
await connection()
return { title: 'Slow Page' }
}
async function DynamicContent() {
await connection()
return <p id="slow-content">Slow content</p>
}
export default function SlowPage() {
return (
<main>
<Suspense fallback={<p id="slow-fallback">loading…</p>}>
<DynamicContent />
</Suspense>
</main>
)
}