Conversation
@vinext/cloudflare
create-vinext-app
@vinext/types
vinext
@cloudflare/workers-response-store
commit: |
Performance benchmarksCompared 0 improved · 0 regressed · 6 within ±1.5%
View detailed results and traces 🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head |
Render generated metadata through the same hidden Suspense boundary in streaming and blocking placement, and pair the boundary with a blocker that holds the response shell on that same resolution. HTML-limited bots keep receiving the tags in the initial document head while the body continues streaming, and the blocking path hydrates from the same tree as the streaming path instead of a separate eager head render. Bypass PPR fallback shells for requests that require blocking metadata: a fallback shell has already closed its head before the dynamic render resumes, so tags resolved during the resume could never reach the document head. Ported from Next.js vercel/next.js@7d42c9d, upstream coverage in test/e2e/app-dir/metadata-streaming-cache-components/metadata-streaming-cache-components-custom-bots.test.ts. Tests: - builds blocking-placement elements without awaiting generated metadata (new) - bypasses the PPR fallback shell for an html-limited bot and renders the page (new) - keeps blocking metadata in the head for an HTML-limited bot while the body streams (new) - streams generated metadata into the body for a DOM-capable browser (new) - blocks the shell on generated metadata and hydrates without errors (Playwright, new)
|
CI note: the first run (8ac2acf) failed in That failure is unrelated to this change:
Re-triggered by amending to |
Fixes #3320
Summary
headwhile the body keeps streaming, and the blocking path hydrates from the same tree as the streaming path instead of a separate eager head render.vercel/next.js@7d42c9d; upstream coverage:test/e2e/app-dir/metadata-streaming-cache-components/metadata-streaming-cache-components-custom-bots.test.ts.Files:
server/app-page-element-builder.ts,server/app-page-route-wiring.tsx,server/app-page-ppr-runtime.ts.Test plan
New tests (each fails if its source change is reverted):
tests/app-page-element-builder.test.ts— builds blocking-placement elements without awaiting generated metadata (times out on the pre-fix eager await).tests/app-page-dispatch.test.ts— bypasses the PPR fallback shell for an html-limited bot and renders the page (plus a streaming-capable control that still serves the shell).tests/app-router-production-server.test.ts— bot gets title/description in</head>whilemetadata-streaming-bot-contentstreams in a later chunk; browser gets the title streamed in the body. New fixturetests/fixtures/app-basic/app/metadata-streaming-bot/page.tsx.tests/e2e/app-router/nextjs-compat/metadata.spec.ts— bot-UA hydration: one head title, no body title, streamed content visible, zero console/page errors.Updated: routes html-limited bot metadata errors through an unsuspended outlet (both placements now share the boundary).
Local CI parity run before pushing:
vp run build,vp check,vp run knip,node scripts/ci-integration-shard.mjs --check --shard-total=10,vp test run --project unit(10200 passed; only pre-existing macOS-only failure), fullvp test run(12256 passed; remaining failures reproduce at base or pass in isolation), and Playwright projectsapp-router,app-router-isr-prod,app-router-bfcache,ppr-impact-demo,app-router-chrome-browser-specific.Note: the new bot tests use
Twitterbot/1.0rather than Googlebot — Googlebot executes JS, so it is a headless-browser bot that streams, not an HTML-limited bot (utils/html-limited-bots.ts).