[PR #514] [MERGED] fix: Pages Router SSR streaming #637

Closed
opened 2026-05-06 13:09:14 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/514
Author: @JaredStowell
Created: 3/13/2026
Status: Merged
Merged: 3/22/2026
Merged by: @southpolesteve

Base: mainHead: jstowell/pages-prod-ssr-streaming


📝 Commits (10+)

  • 914e483 fix pages router streaming
  • 4565b58 handle regressions
  • 25dc13a fix: align pages response merge behavior
  • d2b4655 fix: drop stale worker content-length headers
  • 4877173 fix: preserve no-body rewrite parity
  • 46e7de5 Merge upstream/main into jstowell/pages-prod-ssr-streaming
  • 7def74c fix: cancel streamed HEAD responses
  • 552e07c test: support merged prod server shape
  • f0dd479 Merge upstream/main into jstowell/pages-prod-ssr-streaming
  • 596f0ae Fix compressed Pages SSR streaming

📊 Changes

13 files changed (+1432 additions, -82 deletions)

View changed files

📝 packages/vinext/src/deploy.ts (+52 -4)
📝 packages/vinext/src/entries/pages-server-entry.ts (+8 -1)
📝 packages/vinext/src/server/prod-server.ts (+169 -24)
📝 packages/vinext/src/server/worker-utils.ts (+58 -3)
📝 tests/__snapshots__/entry-templates.test.ts.snap (+28 -15)
📝 tests/deploy.test.ts (+128 -0)
📝 tests/ecosystem.test.ts (+1 -1)
📝 tests/features.test.ts (+402 -0)
📝 tests/fixtures/pages-basic/middleware.ts (+7 -0)
📝 tests/fixtures/pages-basic/pages/ssr-res-end.tsx (+3 -1)
tests/fixtures/pages-basic/pages/streaming-gssp-content-length.tsx (+39 -0)
tests/fixtures/pages-basic/pages/streaming-ssr.tsx (+27 -0)
📝 tests/pages-router.test.ts (+510 -33)

📄 Description

Fix the Pages Router Node production SSR path so responses stay streamed instead of being fully buffered before send.

Previously, the Pages SSR path in prod-server.ts drained the rendered Response with response.arrayBuffer() before writing it to the socket. That removed progressive streaming, copied the full HTML payload, and increased TTFB and memory usage on large responses.

This change preserves the original Response.body stream through the existing streamed Node response path and fixes the related response-merge edge cases that showed up once streaming was preserved.

Changes

  • switch the Pages Router SSR production path over to the streamed Node response sender instead of buffering the full body first
  • preserve streamed bodies while still applying middleware status/header overrides
  • handle no-body rewrite statuses (204, 205, 304) correctly when middleware rewrites a streamed Pages SSR response
  • strip body/framing headers for no-body responses
  • strip stale Content-Length from streamed Pages SSR responses, including values inherited from:
    • getServerSideProps
    • middleware rewrites
  • add production regression coverage for:
    • incremental Pages SSR streaming
    • middleware header preservation on streamed responses
    • no-body rewrite statuses on streamed Pages SSR
    • stale Content-Length from getServerSideProps
    • stale Content-Length from middleware rewrites
  • add Pages Router fixture coverage for delayed streaming and bad content-length cases

Why

Pages Router SSR already produces a streamed Response, but the Node prod server was materializing that stream into a full buffer before sending it.

This PR preserves streaming behavior and also handles the edge cases with the streamed merge path:

  • bodyless middleware rewrite statuses like 204, 205, and 304
  • stale Content-Length on streamed SSR responses

Testing

  • pnpm test tests/pages-router.test.ts
  • pnpm test tests/features.test.ts -t "mergeWebResponse"
  • pnpm run fmt
  • pnpm run typecheck

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/514 **Author:** [@JaredStowell](https://github.com/JaredStowell) **Created:** 3/13/2026 **Status:** ✅ Merged **Merged:** 3/22/2026 **Merged by:** [@southpolesteve](https://github.com/southpolesteve) **Base:** `main` ← **Head:** `jstowell/pages-prod-ssr-streaming` --- ### 📝 Commits (10+) - [`914e483`](https://github.com/cloudflare/vinext/commit/914e4830b7cb431fe13a41a9bd692e42aa626ba9) fix pages router streaming - [`4565b58`](https://github.com/cloudflare/vinext/commit/4565b5863cec39276f5ff2021fbac8f121de7ff2) handle regressions - [`25dc13a`](https://github.com/cloudflare/vinext/commit/25dc13ab7c0e42313284e4643ed81587abfde09e) fix: align pages response merge behavior - [`d2b4655`](https://github.com/cloudflare/vinext/commit/d2b46553f0ff15cadaab842fe2a59dd2872fa40d) fix: drop stale worker content-length headers - [`4877173`](https://github.com/cloudflare/vinext/commit/48771731c8b50ebf8bd9b5ef9e0c6019a8556aca) fix: preserve no-body rewrite parity - [`46e7de5`](https://github.com/cloudflare/vinext/commit/46e7de5dfdf488cb6964e0797be73938e8cf95f7) Merge upstream/main into jstowell/pages-prod-ssr-streaming - [`7def74c`](https://github.com/cloudflare/vinext/commit/7def74c80c9a3cad7a521a1aaebe0da76e3ba66c) fix: cancel streamed HEAD responses - [`552e07c`](https://github.com/cloudflare/vinext/commit/552e07cd15a856a72a55914ca8b6d172d2a2b749) test: support merged prod server shape - [`f0dd479`](https://github.com/cloudflare/vinext/commit/f0dd479644102659746208e9b2d33d8bc25d0f6f) Merge upstream/main into jstowell/pages-prod-ssr-streaming - [`596f0ae`](https://github.com/cloudflare/vinext/commit/596f0ae708853ff765db4485227e9fd801100d40) Fix compressed Pages SSR streaming ### 📊 Changes **13 files changed** (+1432 additions, -82 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/deploy.ts` (+52 -4) 📝 `packages/vinext/src/entries/pages-server-entry.ts` (+8 -1) 📝 `packages/vinext/src/server/prod-server.ts` (+169 -24) 📝 `packages/vinext/src/server/worker-utils.ts` (+58 -3) 📝 `tests/__snapshots__/entry-templates.test.ts.snap` (+28 -15) 📝 `tests/deploy.test.ts` (+128 -0) 📝 `tests/ecosystem.test.ts` (+1 -1) 📝 `tests/features.test.ts` (+402 -0) 📝 `tests/fixtures/pages-basic/middleware.ts` (+7 -0) 📝 `tests/fixtures/pages-basic/pages/ssr-res-end.tsx` (+3 -1) ➕ `tests/fixtures/pages-basic/pages/streaming-gssp-content-length.tsx` (+39 -0) ➕ `tests/fixtures/pages-basic/pages/streaming-ssr.tsx` (+27 -0) 📝 `tests/pages-router.test.ts` (+510 -33) </details> ### 📄 Description Fix the Pages Router Node production SSR path so responses stay streamed instead of being fully buffered before send. Previously, the Pages SSR path in `prod-server.ts` drained the rendered `Response` with `response.arrayBuffer()` before writing it to the socket. That removed progressive streaming, copied the full HTML payload, and increased TTFB and memory usage on large responses. This change preserves the original `Response.body` stream through the existing streamed Node response path and fixes the related response-merge edge cases that showed up once streaming was preserved. ## Changes - switch the Pages Router SSR production path over to the streamed Node response sender instead of buffering the full body first - preserve streamed bodies while still applying middleware status/header overrides - handle no-body rewrite statuses (`204`, `205`, `304`) correctly when middleware rewrites a streamed Pages SSR response - strip body/framing headers for no-body responses - strip stale `Content-Length` from streamed Pages SSR responses, including values inherited from: - `getServerSideProps` - middleware rewrites - add production regression coverage for: - incremental Pages SSR streaming - middleware header preservation on streamed responses - no-body rewrite statuses on streamed Pages SSR - stale `Content-Length` from `getServerSideProps` - stale `Content-Length` from middleware rewrites - add Pages Router fixture coverage for delayed streaming and bad content-length cases ## Why Pages Router SSR already produces a streamed `Response`, but the Node prod server was materializing that stream into a full buffer before sending it. This PR preserves streaming behavior and also handles the edge cases with the streamed merge path: - bodyless middleware rewrite statuses like `204`, `205`, and `304` - stale `Content-Length` on streamed SSR responses ## Testing - `pnpm test tests/pages-router.test.ts` - `pnpm test tests/features.test.ts -t "mergeWebResponse"` - `pnpm run fmt` - `pnpm run typecheck` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:09:14 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#637
No description provided.