Skip to content

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

@switz

Description

@switz

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions