vitejs/vite-plugin-react

@vitejs/plugin-rsc — expose Node.js stream APIs (renderToPipeableStream, createFromNodeStream)

Offen

#1.162 geöffnet am 23.03.2026

 (1 Kommentar) (0 Reaktionen) (0 zugewiesene Personen)TypeScript (251 Forks)auto 404
good first issuep2-nice-to-have 🍰plugin: rsc

Repository-Metriken

Stars
 (1.094 Sterne)
PR-Merge-Metriken
 (PR-Metriken ausstehend)

Beschreibung

Related plugins

Description

The vendored react-server-dom packages include Node.js-native stream APIs that are significantly faster than their Web Streams equivalents on Node.js, but @vitejs/plugin-rsc only re-exports the Web Streams variants.

What exists but isn't exposed

  • renderToReadableStream (RSC server) — in rsc.js — ✅ exported
  • renderToPipeableStream (RSC server) — in vendor/react-server-dom/server.node.js — ❌ not exported
  • createFromReadableStream (SSR client) — in rsc.js — ✅ exported
  • createFromNodeStream (SSR client) — in vendor/react-server-dom/cjs/...-client.node.*.js — ❌ not exported

On Node.js, Web Streams are a pure-JavaScript reimplementation. Every reader.read() allocates a Promise, every pipeThrough builds a microtask chain. Node.js native streams use C++ libuv buffers with zero per-chunk Promise overhead.

In benchmarking this: switching just the SSR HTML output from renderToReadableStream to renderToPipeableStream (react-dom/server) cut render times measurably. But the RSC Flight stream — which feeds SSR via createFromReadableStream — is still locked to Web Streams because the plugin doesn't expose the Node.js alternatives.

The full ideal chain on Node.js would be:

  RSC: renderToPipeableStream → Node Readable (Flight data)
  SSR: createFromNodeStream → decodes Flight via Node Readable
  HTML: renderToPipeableStream (react-dom) → Node Writable (HTML)

Zero Web Streams in the hot path when running on node.js.

Suggested solution

Export the Node.js variants alongside the existing Web Stream APIs, gated by export conditions or as separate entry points:

  // Option A: separate entry point
  import { renderToPipeableStream } from '@vitejs/plugin-rsc/rsc/node'
  import { createFromNodeStream } from '@vitejs/plugin-rsc/ssr/node'

  // Option B: export condition in package.json
  // "node" condition resolves to the file that includes both APIs

The existing Web Streams exports would remain unchanged for CF Workers/edge runtimes where Web Streams are the fast path (V8 C++ built-ins).

Alternative

No response

Additional context

No response

Validations

Contributor Guide