JSPM

  • Created
  • Published
  • Downloads 1072
  • Score
    100M100P100Q106701F
  • License MIT

Vite plugin for React Server Components (RSC)

Package Exports

  • vite-plugin-react-server
  • vite-plugin-react-server/client
  • vite-plugin-react-server/components
  • vite-plugin-react-server/config
  • vite-plugin-react-server/config/createHandlerOptions
  • vite-plugin-react-server/css-loader
  • vite-plugin-react-server/dev-server
  • vite-plugin-react-server/dev-server/cleanupServerAction
  • vite-plugin-react-server/dev-server/configureReactServer
  • vite-plugin-react-server/dev-server/configureRequestHandler
  • vite-plugin-react-server/dev-server/handleServerAction
  • vite-plugin-react-server/dev-server/restartWorker
  • vite-plugin-react-server/directives
  • vite-plugin-react-server/env
  • vite-plugin-react-server/env-loader
  • vite-plugin-react-server/env/plugin
  • vite-plugin-react-server/error
  • vite-plugin-react-server/file-preserver
  • vite-plugin-react-server/helpers
  • vite-plugin-react-server/helpers/handleServerAction
  • vite-plugin-react-server/helpers/resolveStreamElements
  • vite-plugin-react-server/html-worker
  • vite-plugin-react-server/loader
  • vite-plugin-react-server/metrics
  • vite-plugin-react-server/orchestrator
  • vite-plugin-react-server/orchestrator/createPluginOrchestrator
  • vite-plugin-react-server/package.json
  • vite-plugin-react-server/plugin
  • vite-plugin-react-server/react-client
  • vite-plugin-react-server/react-client/plugin
  • vite-plugin-react-server/react-server
  • vite-plugin-react-server/react-server/plugin
  • vite-plugin-react-server/react-static
  • vite-plugin-react-server/react-static/createBuildLoader
  • vite-plugin-react-server/react-static/plugin
  • vite-plugin-react-server/react-static/renderPage
  • vite-plugin-react-server/react-static/rscToHtmlStream
  • vite-plugin-react-server/react-static/temporaryReferences
  • vite-plugin-react-server/register
  • vite-plugin-react-server/rsc-worker
  • vite-plugin-react-server/server
  • vite-plugin-react-server/static
  • vite-plugin-react-server/storybook
  • vite-plugin-react-server/stream
  • vite-plugin-react-server/stream/client
  • vite-plugin-react-server/stream/createFromNodeStream
  • vite-plugin-react-server/stream/createHtmlStream
  • vite-plugin-react-server/stream/createRenderToPipeableStreamHandler
  • vite-plugin-react-server/stream/createRscStream
  • vite-plugin-react-server/stream/handleRscStream
  • vite-plugin-react-server/stream/server
  • vite-plugin-react-server/transformer
  • vite-plugin-react-server/transformer/plugin
  • vite-plugin-react-server/types
  • vite-plugin-react-server/utils
  • vite-plugin-react-server/utils/rsc-client
  • vite-plugin-react-server/vendor
  • vite-plugin-react-server/vendor.client
  • vite-plugin-react-server/vendor.server
  • vite-plugin-react-server/vendor.static
  • vite-plugin-react-server/virtual
  • vite-plugin-react-server/worker

Readme

vite-plugin-react-server

React Server Components for plain Vite on stable React — no framework, no experimental builds. One vite build --app prerenders your pages to static HTML + RSC payloads and emits your components as portable ESM that runs under any HTTP server: static hosting, Express/Hono, or anything in between.

It works in BOTH Node module conditions, by design: the dev server and the build run with or without --conditions react-server, and whichever side your main thread is on, a worker thread mirrors the other half (server components need a react-server context, client hydration needs a react-client one — you always have both). Running the main thread under react-server is an optional optimization — slightly faster, better stack traces — never a requirement.

Install

npm install -D vite-plugin-react-server react react-dom

vprs 2.0 runs on stable React 19.2+. The react-server-dom-esm transport ships inside the react-server-loader dependency (installed automatically), so you no longer install a transport or an experimental React build yourself. Upgrading from 1.x? See the migration notes.

Minimal Example

// vite.config.ts
import { defineConfig } from "vite";
import { vitePluginReactServer } from "vite-plugin-react-server";

export default defineConfig({
  plugins: vitePluginReactServer({
    moduleBase: "src",
    Page: "src/page.tsx",
    build: { pages: ["/"] },
  }),
});
// src/page.tsx
export const Page = ({ url }: { url: string }) => <div>Hello from {url}</div>;
# Dev server
npx vite

# Build (static site + server/client ESM)
npx vite build --app

# Same build, react-server main thread — optional: a bit faster, better stack traces
NODE_OPTIONS='--conditions react-server' vite build --app

Build Output

dist/
├── static/          # Deployable to any static host
│   ├── index.html   # Pre-rendered HTML
│   └── index.rsc    # RSC payload for client navigation
├── client/          # Client-side ESM modules (for SSR)
└── server/          # Server-side ESM modules (with server actions)

dist/static/ is a complete static site. dist/client/ and dist/server/ are ESM modules you can import in your own Express/Hono/Node server.

Client components

vprs recognises a file as a client module when either of these is true:

  • the filename matches (^|[\/.])client\.[cm]?[jt]sx?$ — i.e. Button.client.tsx, bar.client.mjs, or the standalone basename src/client.tsx / client.tsx, or
  • the file starts with a top-of-file "use client" directive (leading whitespace, line/block comments, and an optional "use strict" prologue are tolerated above it).

Either is sufficient. Substrings like clientUtils.tsx, clientId.ts, or clients.tsx are not treated as client modules, and a "use client" directive placed after real code does not count.

// src/components/Counter.tsx  ← no `.client.` suffix needed
"use client";
import { useState } from "react";
export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

See Getting Started.

Third-party client-component packages

Component libraries like Chakra UI, MUI, Mantine, react-aria, and framer-motion are client-only — their components rely on React context/state and must run inside a client boundary, the same constraint they carry under Next.js's App Router. Use them within a "use client" component (commonly a small provider wrapper); they can't be imported directly into a server component. This isn't a vprs limitation — e.g. Chakra's own Next.js App Router guide requires wrapping ChakraProvider in a 'use client' component.

vprs auto-detects these so they're treated correctly at build start: any package with react in its peerDependencies is classified as a client package (using vitefu.crawlFrameworkPkgs). Two escape hatches if needed:

vitePluginReactServer({
  // Force a package into the list (e.g. one that doesn't peerDep react)
  clientPackages: ["@my/internal-ui"],
  // Skip a detected one (e.g. devDeps Storybook bringing along @storybook/react)
  excludeClientPackages: ["@storybook/react", "@storybook/react-vite"],
});

Storybook

vprs ships a Storybook preset — add one line and your RSC app's components build and render in Storybook:

// .storybook/main.ts
export default {
  framework: { name: "@storybook/react-vite", options: {} },
  addons: ["vite-plugin-react-server/storybook"],
};

It strips the vprs plugin from Storybook's builder, resolves the react-server-dom-esm transport (from react-server-loader), and silences "use client"/"use server" directive noise. See Storybook for details. (Requires vprs ≥ 1.9.0.)

Documentation

Doc What it covers
Getting Started Install → first page → dev server → build → deploy
Storybook One-line Storybook support for vprs apps
Build Output What the build produces, how to use the ESM modules
Configuration All plugin options
CSS Handling Inline/linked CSS, CSS modules, the Css component
Server Actions "use server" directives, form actions, hosting
Examples Static site, dynamic server, server actions, custom routing
Troubleshooting Common errors and fixes
API Reference Exported functions, types, and components

Internals (contributors)

Doc What it covers
Architecture Condition system, module structure, plugin composition
Transformer How "use client" / "use server" directives are processed
Workers RSC and HTML worker threads

Maintenance

Doc What it covers
Releasing Version bumps, publishing, demo updates
React Compatibility Vendored ESM transport, type system

Requirements

  • Node.js 22.0.0+ (the build uses node:fs/promises#glob, which landed in 22)
  • Stable React 19.2+ (react / react-dom at ^19.2.7). As of 2.0 the RSC server APIs vprs relies on (prerenderToNodeStream, the react-server transport exports) are part of stable React, so no experimental build is required. The matching react-server-dom-esm transport is provided by the react-server-loader dependency; experimental React still works if you want the newest RSC features. See React Compatibility.
  • Vite 6+

TypeScript

{
  "compilerOptions": {
    "types": ["vite/client", "vite-plugin-react-server/virtual"]
  }
}

License

MIT