Skip to content

vite preview HTTP/2: @polka/compression wrapping breaks text/event-stream — concurrent fetches stall on the same connection #22654

Description

@rsergeenko

Describe the bug

vite preview unconditionally registers @polka/compression ahead of every response (packages/vite/src/node/preview.ts:239 — app.use(compression())). When a request has Accept-Encoding: gzip, polka wraps res.writeHead/write/end/on and defers writeHead to its start() function — even when the response is text/event-stream and won't actually be compressed (chunked SSE has no Content-Length, fails polka's size >= threshold check).

Under HTTP/2 (which vite preview enables when preview.https is set), this wrapping corrupts the HTTP/2 stream lifecycle when the SSE stream is aborted client-side. Other fetch calls multiplexed on the same connection get stuck pending for 10–30 seconds before resolving, or never resolve. Page navigations away from any route that holds an open SSE stream stall visibly.

The compression itself is not the issue — it's correctly skipped for SSE due to the size threshold. The bug is in the proxying of res methods that happens before the compression decision.

Suggested fix

Skip polka's response wrapping for text/event-stream in vite preview. Possible shapes:

  • bump the bundled @polka/compression once lukeed/polka#221 or equivalent lands
  • guard app.use(compression()) in packages/vite/src/node/preview.ts to skip SSE paths
  • expose a preview.compression option so consumers can opt out

Reproduction

https://github.com/rsergeenko/vite-preview-sse-http2-repro

Steps to reproduce

  1. npm install && npm run build && npm run preview
  2. Open https://localhost:4173/ (accept the self-signed cert)
  3. Click Open SSE — opens a long-lived text/event-stream connection via fetch
  4. Wait ~2 seconds (a couple of events stream)
  5. Click Fetch /data — issues a concurrent GET /data (small JSON response)
  6. DevTools → Network: observe /data sits pending for 10–30 seconds before resolving

Expected: /data resolves in single-digit ms.

System Info

- Vite 8.0.16 (also reproduces on 7.x)
- Node 22.x
- macOS 25.5.0, Chromium 148
- @polka/compression 1.0.0-next.25 (bundled with Vite)

Used Package Manager

yarn

Logs

No response

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions