API Reference
This document provides a comprehensive reference for the Vite React Server Plugin's API.
Plugin Options
The plugin accepts a configuration object that satisfies the StreamPluginOptions type:
import type { StreamPluginOptions } from "vite-plugin-react-server/types";
export const config = {
moduleBase: 'src',
// ... options
} satisfies StreamPluginOptions;
Core Options
| Option | Type | Description | Example |
|---|---|---|---|
moduleBase | string | Root directory for project modules | "src" |
moduleBasePath | string | Second argument to renderToPipeableStream | "/my-repo/" |
moduleBaseURL | string | Requests from this base | "/my-repo/" |
publicOrigin | string | Origin for moduleBaseURL | "https://username.github.io" |
Page | (url: string) => string | Maps URLs to page component files | - |
props | (url: string) => string | Maps URLs to props files | - |
Html | React.ComponentType<HtmlProps> | Wrapper component for production pages | - |
pageExportName | string | Name of the page export | "Page" |
propsExportName | string | Name of the props export | "props" |
clientEntry | string | Optional explicit client entry. Not needed when index.html has a <script type="module" src> for the entry — Vite discovers it itself. See Configuration. | - |
htmlWorkerPath | string | Path to custom HTML worker | - |
rscWorkerPath | string | Path to custom RSC worker | - |
CssCollector | React.ComponentType<CssCollectorProps> | Component for collecting CSS (handles both inline and non-inline modes) | - |
build | BuildOptions | Build configuration | - |
css | CssOptions | CSS handling configuration | - |
verbose | boolean | Enable verbose logging | true |
rscTimeout | number | Timeout in milliseconds for RSC operations | 5000 |
htmlTimeout | number | Timeout in milliseconds for HTML generation operations | 15000 |
htmlWorkerStartupTimeout | number | Timeout in milliseconds for HTML worker startup | 5000 |
rscWorkerStartupTimeout | number | Timeout in milliseconds for RSC worker startup | 5000 |
onMetrics | (metrics: RenderMetrics) => void | Callback for build metrics | - |
onEvent | (event: PluginEvent) => void | Callback for plugin events | - |
normalizer | InputNormalizer | Custom input normalizer | - |
moduleID | (id: string) => string | Custom module ID transformer | - |
pipeableStreamOptions | ReactServerDomEsmOptions | Options for React's renderToPipeableStream | - |
Build Options
| Option | Type | Description | Default |
|---|---|---|---|
pages | string[] | Routes to generate | [] |
dir | string | Base directory | "dist" |
client | string | Client assets directory | "client" |
server | string | Server assets directory | "server" |
static | string | Static output directory | "static" |
hash | string | Hash for client files | "hash" |
preserveModulesRoot | boolean | When true, preserves the moduleBase directory (e.g. src/) in output paths. When false, strips it from output paths. | false |
assetsDir | string | Assets directory | "assets" |
api | string | API output directory | "api" |
outDir | string | Output directory | "dist" |
rscOutputPath | string | RSC output filename | "index.rsc" |
htmlOutputPath | string | HTML output filename | "index.html" |
entryFile | (chunk: PreRenderedChunk, ssr: boolean) => string | Custom entry file naming | - |
chunkFile | (chunk: PreRenderedChunk, ssr: boolean) => string | Custom chunk file naming | - |
assetFile | (asset: PreRenderedAsset, ssr: boolean) => string | Custom asset file naming | - |
extensionMap | Record<string, string> | Custom file extensions | - |
moduleExtension | string | Module file extension | ".js" |
jsExtension | string | JavaScript file extension | ".js" |
cssExtension | string | CSS file extension | ".css" |
htmlExtension | string | HTML file extension | ".html" |
jsonExtension | string | JSON file extension | ".json" |
rscExtension | string | RSC file extension | ".rsc" |
cssModuleExtension | string | CSS module file extension | ".css.js" |
nodeExtension | string | Node.js file extension | ".node" |
CSS Options
| Option | Type | Description | Default |
|---|---|---|---|
inlineCss | boolean | Disable inline CSS in HTML | true |
inlineThreshold | number | Size threshold for inlining (bytes) | 4096 |
inlinePatterns | RegExp[] | Patterns for files to always inline | [] |
linkPatterns | RegExp[] | Patterns for files to always link | [] |
Loader Options
| Option | Type | Description | Default |
|---|---|---|---|
importServerPath | string | Path for server imports | "vite-plugin-react-server/loader" |
importClientPath | string | Path for client imports | "vite-plugin-react-server/loader" |
registerClientReferenceName | string | Name for client reference registration | "registerClientReference" |
registerServerReferenceName | string | Name for server reference registration | "registerServerReference" |
serverDirective | RegExp | Pattern to match server directives | /^"use server"$/ |
clientDirective | RegExp | Pattern to match client directives | /^"use client"$/ |
directivePattern | RegExp | General pattern for directives | /^"use (server|client)"$/ |
allowedDirectives | string[] | List of allowed directive names | ["use server", "use client"] |
mode | "development" | "production" | "test" | Loader mode | "development" |
isServerFunctionCode | (code: string, moduleId?: string) => boolean | Custom server function detection | - |
isClientComponentCode | (code: string, moduleId?: string) => boolean | Custom client-module detection (source + filename) | detectClientModule (filename .client.* or top-of-file "use client") |
isClientComponentByCode | (code: string) => boolean | Custom client-module detection (source only) | detectClientModule |
isClientComponentByName | (moduleId: string) => boolean | Custom client-module detection (filename only) | detectClientModule; a custom autoDiscover.clientPattern takes precedence |
getDirectiveType | (directive: string, moduleId?: string) => "client" | "server" | undefined | Custom directive type detection | - |
Auto-Discovery Options
| Option | Type | Description | Default |
|---|---|---|---|
cssPattern | RegExp | string | Pattern to match CSS files | /.css$/ |
cssModulePattern | RegExp | string | Pattern to match CSS module files | /.css.js$/ |
clientPattern | RegExp | string | Pattern to match client-module filenames. Anchored so substrings like clientUtils.tsx are not matched; the standalone basename client.tsx matches alongside the dotted-suffix form Foo.client.tsx. A top-of-file "use client" directive is recognised independently. | /(^|[/.])client.[cm]?[jt]sx?$/ |
serverPattern | RegExp | string | Pattern to match server function files | /.server.(js|ts|jsx|tsx)$/ |
htmlPattern | RegExp | string | Pattern to match HTML files | /.html$/ |
jsonPattern | RegExp | string | Pattern to match JSON files | /.json$/ |
modulePattern | RegExp | string | Pattern to match module files | /.(js|ts|jsx|tsx)$/ |
rscPattern | RegExp | string | Pattern to match RSC files | /.rsc$/ |
pagePattern | RegExp | string | Pattern to match page files | /[Pp]age.(js|ts|jsx|tsx)$/ |
propsPattern | RegExp | string | Pattern to match props files | /[Pp]rops.(js|ts|jsx|tsx)$/ |
dotPattern | RegExp | string | Pattern to match dot files | /^.[^/]+$/ |
nodePattern | RegExp | string | Pattern to match Node.js native modules | /.node$/ |
vendorPattern | RegExp | string | Pattern to match vendor files | /node_modules|_virtual/ |
virtualPattern | RegExp | string | Pattern to match virtual files | /^virtual:/ |
Component Props
HtmlProps
Props passed to the Html wrapper component during static generation:
type HtmlProps = {
pageProps?: any;
Page: PageComponentType;
route: string;
url: string;
projectRoot: string;
moduleBase: string;
moduleBaseURL: string;
moduleBasePath: string;
moduleRootPath: string;
cssFiles: Map<string, CssContent>;
manifest: Manifest;
Root: RootComponentType | typeof React.Fragment;
globalCss: Map<string, CssContent>;
as?: keyof JSX.IntrinsicElements;
};
RootProps
Props for the Root component that wraps page content:
type RootProps = {
as: keyof JSX.IntrinsicElements;
cssFiles?: Map<string, CssContent>;
pageProps?: any;
Page: PageComponentType;
id?: string;
};
CssContent
CSS content can be either inline (string) or linked (object with href):
type CssContent<InlineCSS extends boolean = boolean> =
InlineCSS extends true ? string : { href: string };
Build Configuration
BuildConfig
Configuration for build processes:
interface BuildConfig {
pages: string[];
client?: string; // Default: "client"
server?: string; // Default: "server"
static?: string; // Default: "static"
outDir?: string; // Default: "dist"
assetsDir?: string; // Default: "assets"
rscOutputPath?: string; // Default: "index.rsc"
htmlOutputPath?: string; // Default: "index.html"
preserveModulesRoot?: boolean;
hash?: string;
edge?: EdgeBuildConfig;
}
build.edge
Single-isolate edge bundle (additive; ON by default). See Edge / Single-Isolate.
// build.edge?: boolean | EdgeBuildConfig (default: true)
// true / omitted → emit with defaults
// false → opt out
// { … } → emit, with overrides
interface EdgeBuildConfig {
outDir?: string; // Default: "server-edge" (under build.outDir)
minify?: boolean; // Default: true — edge runtimes cap bundle size
}
Drive the baked render.js with createEdgeHandler from
vite-plugin-react-server/stream: renderRouteToDocument for a flash-free
inline-flight document, handleRouteAction for the baked server-action gate, or
the low-level renderRouteToFlight producer.
CssConfig
Configuration for CSS handling:
interface CssConfig {
inlineCss?: boolean; // Default: false
purgeCss?: boolean; // Default: false
inlineThreshold?: number; // Default: 4096 (4KB)
inlinePatterns?: RegExp[];
linkPatterns?: RegExp[];
}
preserveModulesRoot Behavior
The build.preserveModulesRoot option controls how the moduleBase directory appears in build output paths:
When preserveModulesRoot: true (preserve paths)
- Input:
src/page/home.tsx - Output:
dist/client/src/page/home.js - Behavior: The
src/directory is preserved in the output path
When preserveModulesRoot: false (strip paths - default)
- Input:
src/page/home.tsx - Output:
dist/client/page/home.js - Behavior: The
src/directory is removed from the output path
This option is useful when you want to maintain your source directory structure in the build output, especially for debugging or when integrating with tools that expect specific path structures.
Event System
PluginEvent
Events emitted during build processes:
type PluginEvent =
| { type: 'build:start'; data: { target: string } }
| { type: 'build:end'; data: { target: string; duration: number } }
| { type: 'page:build:start'; data: { url: string; target: string } }
| { type: 'page:build:end'; data: { url: string; target: string; duration: number } }
| { type: 'error'; data: { message: string; stack?: string } }
| { type: 'warning'; data: { message: string } };
BuildMetrics
Metrics collected during builds:
interface BuildMetrics {
buildTime: number;
htmlSize: number;
rscSize: number;
cssSize: number;
jsSize: number;
pageCount: number;
errorCount: number;
warningCount: number;
}
Worker Messages
WorkerMessage
Messages sent between main thread and workers:
type WorkerMessage =
| { type: 'render'; data: RenderRequest }
| { type: 'result'; data: RenderResult }
| { type: 'error'; data: { message: string; stack?: string } }
| { type: 'ready'; data: {} };
RenderRequest
Request structure for rendering:
interface RenderRequest {
url: string;
pageProps?: any;
moduleBaseURL: string;
cssFiles: CssFile[];
globalCss: CssFile[];
}
RenderResult
Result structure from rendering:
interface RenderResult {
html: string;
rsc: string;
css: string;
duration: number;
}
Type Definitions
Component Types
// Page component — receives page props, returns React element
type PageComponentType = (props: any) => React.ReactNode;
// Root component — wraps page with CSS and layout
type RootComponentType = (props: RootProps) => React.ReactNode;
// Html component — outer HTML shell for static generation
type HtmlComponentType = (props: HtmlProps) => React.ReactNode;
// CSS component — renders inline <style> or <link> tags
type CssComponentType = (props: CssProps) => React.ReactNode;
Note: The full type signatures use generics constrained by a
ViteReactServerComponentsPlugininterface for advanced type customization. The simplified versions above cover most use cases. Seeplugin/types.tsfor the full generic signatures.
Environment Detection
// Check current execution context
function getCondition(): string | null;
// Environment-specific configurations
const RSC_LOADER = {
development: {
importServerPath: "react-server-dom-esm/server.node",
importClientPath: "react-server-dom-esm/server.node",
registerClientReferenceName: "registerClientReference",
registerServerReferenceName: "registerServerReference"
},
production: {
importServerPath: "react-server-dom-esm/server",
importClientPath: "react-server-dom-esm/server",
registerClientReferenceName: "registerClientReference",
registerServerReferenceName: "registerServerReference"
}
};
Directive Patterns
Server Directives
const SERVER_DIRECTIVE = /^["']use server["'];?\s*$/gm;
Client Directives
const CLIENT_DIRECTIVE = /^["']use client["'];?\s*$/gm;
Validation Rules
const DIRECTIVE_CONFIGS = {
client: {
functionLevel: false,
target: 'client',
validate: (params) => params.index === 0, // Must be at file start
warning: "'use client' directive is only allowed at the top of a file"
},
server: {
functionLevel: true,
target: 'server',
validate: (params) => {
const before = params.code.slice(0, params.index).trim();
return before === '' || before.endsWith('\n');
},
warning: "File-level directives must be at the top of the file, before any other code"
}
};
File Patterns
Auto-Discovery Patterns
const AUTO_DISCOVER = {
modulePattern: /\.(m|c)?(j|t)sx?$/,
serverPattern: /(?:\.\/)?server(?:\.(m|c)?(j|t)sx?)?$/,
clientPattern: /(^|[\/.])client\.[cm]?[jt]sx?$/,
pagePattern: /(?:\.\/)?page(?:\.(m|c)?(j|t)sx?)?$/,
propsPattern: /(?:\.\/)?props(?:\.(m|c)?(j|t)sx?)?$/,
cssPattern: /\.css$/,
jsonPattern: /\.json$/,
htmlPattern: /\.html$/,
rscPattern: /\.rsc$/,
};
A file is treated as a client module when either the filename matches clientPattern or the source starts with a top-of-file "use client" directive. Both mechanisms are first-class — neither is a fallback to the other.
Extension Mapping
const EXTENSION_MAP = {
".js": ".js",
".ts": ".js",
".jsx": ".js",
".tsx": ".js",
".css": ".css",
".json": ".json",
".html": ".html",
".rsc": ".rsc",
".client": ".client.js",
".server": ".server.js",
};
Testing Utilities
doBuild Function
function doBuild(options: {
projectRoot: string;
build: BuildConfig;
verbose?: boolean;
}): Promise<PluginEvent[]>;
Test Configuration
const testConfig: StreamPluginOptions = {
moduleBase: "src",
Page: (url) => `src/page.tsx`,
build: { pages: ["/"] },
verbose: true,
onEvent: (event) => console.log(event),
onMetrics: (metrics) => console.log(metrics),
};
Import Paths
Main Plugin
import { vitePluginReactServer } from "vite-plugin-react-server";
Client Plugin
import { vitePluginReactClient } from "vite-plugin-react-server/client";
Server Plugin
import { vitePluginReactServer } from "vite-plugin-react-server/server";
Stream Helpers
import { createRscStream, createHtmlStream, handleRscStream } from "vite-plugin-react-server/stream";
Utils (Conditional Export)
// Default condition (client) — includes createReactFetcher, setupRscHmr, useRscHmr
import { createReactFetcher, setupRscHmr, useRscHmr, callServer } from "vite-plugin-react-server/utils";
// react-server condition — excludes browser-only modules
import { callServer, env, routeToURL } from "vite-plugin-react-server/utils";
For consumers who want to import only the pure helpers (urls, env, routeToURL) without dragging in the optional react-server-dom-esm peer that the RSC-client helpers require, the RSC-client helpers are also available behind their own subpath:
// Opt-in subpath for RSC-client helpers — explicitly requires the
// `react-server-dom-esm` peer to be resolvable (the vprs Vite plugin
// sets this up automatically for RSC apps).
import { createReactFetcher, setupRscHmr, useRscHmr, callServer } from "vite-plugin-react-server/utils/rsc-client";
Cancelling a superseded RSC fetch
createReactFetcher accepts an AbortSignal. Without one, a flight fetch
that gets superseded — a fast double-navigation, a refetch racing an earlier
fetch — aborts mid-body and the decoder's TypeError: Error in input stream
lands in the nearest error boundary, briefly flashing an error card for a
stream nobody is waiting on anymore.
Have each navigation/refetch own an AbortController, and abort the previous
one before starting the next. A stream cancelled through its signal never
rejects — the stale thenable stays pending (React keeps the current UI) until
the replacing fetch resolves:
let controller: AbortController | undefined;
function navigate(url: string) {
controller?.abort(); // cancel the in-flight stream, silently
controller = new AbortController();
setContent(createReactFetcher({ url, signal: controller.signal }));
}
Genuine flight failures (network errors, decode failures on a stream that was NOT aborted) still reject and reach the error boundary as before.
Storybook preset
A Storybook preset that makes a vprs app build and render in Storybook. Referenced as an addon, not imported directly. See Storybook.
// .storybook/main.ts
export default { addons: ["vite-plugin-react-server/storybook"] };
react-server-dom-esm transport
The react-server-dom-esm transport ships in the
react-server-loader
dependency, which exposes it under public subpaths so non-plugin consumers (e.g.
the Storybook preset) can resolve it. Not typically imported by app code.
// ESM client.browser build (dev/prod conditioned)
import "react-server-loader/client.browser";
In vprs 1.x this was re-hosted under
vite-plugin-react-server/react-server-dom-esm/*. That self-export was removed in 2.0 — import fromreact-server-loaderinstead.
Type Imports
import type {
StreamPluginOptions,
HtmlProps,
RootProps,
BuildConfig,
PluginEvent,
BuildMetrics
} from "vite-plugin-react-server/types";
Component Imports
import { Css } from "vite-plugin-react-server/components";
Configuration Utilities
import { getCondition } from "vite-plugin-react-server/config";
Metric Watcher
The plugin includes a built-in metric watcher that monitors build performance and backpressure:
import { metricWatcher } from "vite-plugin-react-server/metrics";
// Default configuration (enabled by default)
const defaultWatcher = metricWatcher({
maxTime: 200, // Warn if processing takes > 200ms
maxBackpressure: 0, // Warn if any backpressure occurs
});
// Custom configuration
const customWatcher = metricWatcher({
maxTime: 500, // Warn if processing takes > 500ms
maxBackpressure: 5, // Warn if > 5 backpressure occurrences
warnOnly: true, // Only show warnings, not info messages
});
// or simply
export const config = {
moduleBase: "src",
onMetrics: metricWatcher()
}
Metric Watcher Options
| Option | Type | Default | Description |
|---|---|---|---|
maxTime | number | 200 | Maximum processing time in milliseconds before warning |
maxBackpressure | number | 0 | Maximum backpressure occurrences before warning |
warnOnly | boolean | false | Only show warnings, suppress info messages |
warn | function | console.warn | Custom warning function |
info | function | console.info | Custom info function |
Backpressure Monitoring
The metric watcher automatically monitors stream backpressure, which occurs when:
- The file writer is slower than the HTML generation
- The worker communication queue is full
- System resources are constrained
Backpressure warnings help identify performance bottlenecks and potential memory issues.