React Server Components bindings for DOM using Webpack, enabling server-side rendering with streaming support and client-server communication.
—
Static pre-rendering capabilities for React Server Components, enabling build-time generation of server component output for improved performance and SEO.
Pre-renders React Server Components at build time, generating static output that can be served directly or hydrated on the client.
/**
* Pre-renders server components for static generation
* @param model - React server component tree to pre-render
* @param webpackMap - Client manifest for module resolution
* @param options - Optional rendering configuration
* @returns Promise resolving to pre-render result
*/
function unstable_prerender(
model: ReactClientValue,
webpackMap: ClientManifest,
options?: ServerOptions
): Promise<StaticResult>;Usage Examples:
import { unstable_prerender } from "react-server-dom-webpack/static.browser";
// Pre-render a server component at build time
async function generateStaticPage() {
const clientManifest = JSON.parse(
await fs.readFile("./react-client-manifest.json", "utf8")
);
const result = unstable_prerender(
<HomePage posts={staticPosts} />,
clientManifest,
{
identifierPrefix: "static-",
onError: (error) => {
console.error("Static render error:", error);
}
}
);
// Save static output
await fs.writeFile("./dist/home.html", result.prelude);
return result;
}
// Build-time page generation
const pages = [
{ path: "/", component: <HomePage /> },
{ path: "/about", component: <AboutPage /> },
{ path: "/contact", component: <ContactPage /> }
];
for (const page of pages) {
const result = unstable_prerender(page.component, clientManifest);
await saveStaticPage(page.path, result);
}Node.js-specific pre-rendering with stream support for build pipelines.
/**
* Pre-renders server components to Node.js stream for build tools
* @param model - React server component tree to pre-render
* @param webpackMap - Client manifest for module resolution
* @param options - Optional rendering configuration
* @returns ReadableStream containing pre-rendered content
*/
function unstable_prerenderToNodeStream(
model: ReactClientValue,
webpackMap: ClientManifest,
options?: ServerOptions
): ReadableStream;Usage Examples:
import { unstable_prerenderToNodeStream } from "react-server-dom-webpack/static.node";
import { createWriteStream } from "fs";
// Stream pre-rendered content to file
async function prerenderToFile(component, outputPath) {
const clientManifest = JSON.parse(
fs.readFileSync("./react-client-manifest.json", "utf8")
);
const stream = unstable_prerenderToNodeStream(
component,
clientManifest,
{
onError: (error) => console.error("Prerender error:", error),
signal: abortController.signal
}
);
const writeStream = createWriteStream(outputPath);
// Pipe pre-rendered output to file
stream.pipe(writeStream);
return new Promise((resolve, reject) => {
writeStream.on("finish", resolve);
writeStream.on("error", reject);
});
}
// Build-time static generation
await prerenderToFile(<BlogPost post={postData} />, "./dist/blog/post-123.html");Common patterns for integrating static pre-rendering into build workflows.
// build/generatePages.js
import { unstable_prerender } from "react-server-dom-webpack/static.node";
import { loadClientManifest, getAllPosts, getAllPages } from "./utils";
async function generateStaticSite() {
const clientManifest = await loadClientManifest();
const posts = await getAllPosts();
const pages = await getAllPages();
// Generate static pages
for (const page of pages) {
const result = unstable_prerender(
<Page {...page} />,
clientManifest,
{ identifierPrefix: `page-${page.id}-` }
);
await fs.writeFile(`./dist/${page.slug}.html`, result.prelude);
console.log(`Generated: ${page.slug}`);
}
// Generate blog posts
for (const post of posts) {
const result = unstable_prerender(
<BlogPost post={post} />,
clientManifest,
{ identifierPrefix: `post-${post.id}-` }
);
await fs.writeFile(`./dist/blog/${post.slug}.html`, result.prelude);
console.log(`Generated: blog/${post.slug}`);
}
}
generateStaticSite().catch(console.error);// api/revalidate.js
import { unstable_prerender } from "react-server-dom-webpack/static.browser";
export async function POST(request) {
const { path, data } = await request.json();
try {
// Re-generate specific page
const result = unstable_prerender(
<DynamicPage data={data} />,
clientManifest,
{
identifierPrefix: `revalidate-${Date.now()}-`,
onError: (error) => {
console.error(`Revalidation error for ${path}:`, error);
}
}
);
// Update static file
await fs.writeFile(`./dist${path}.html`, result.prelude);
return Response.json({ success: true, path });
} catch (error) {
return Response.json({ error: error.message }, { status: 500 });
}
}// webpack.config.js
const ReactFlightWebpackPlugin = require("react-server-dom-webpack/plugin");
module.exports = {
plugins: [
new ReactFlightWebpackPlugin({
isServer: false,
clientReferences: ["./src/**/*.client.js"]
}),
// Custom plugin for static generation
{
apply(compiler) {
compiler.hooks.afterEmit.tapAsync("StaticGeneration", async (compilation, callback) => {
const { unstable_prerender } = require("react-server-dom-webpack/static.node");
// Generate static pages after build
await generateStaticPages(unstable_prerender);
callback();
});
}
}
]
};Working with pre-render results and their metadata.
// Handle pre-render result
const result = unstable_prerender(<App />, clientManifest);
// Extract different parts of the result
const {
prelude, // Static HTML content
postponed, // Postponed content for streaming
metadata // Additional rendering metadata
} = result;
// Save static content
await fs.writeFile("./static/app.html", prelude);
// Handle postponed content if any
if (postponed) {
await handlePostponedContent(postponed);
}Comprehensive error handling for build-time rendering issues.
import { unstable_prerender } from "react-server-dom-webpack/static.browser";
async function safePrerender(component, clientManifest, options = {}) {
const errors = [];
const result = unstable_prerender(
component,
clientManifest,
{
...options,
onError: (error) => {
errors.push({
message: error.message,
stack: error.stack,
timestamp: new Date().toISOString()
});
// Log error but continue rendering
console.error("Pre-render error:", error);
}
}
);
return {
...result,
errors,
hasErrors: errors.length > 0
};
}
// Use with error reporting
const result = await safePrerender(<HomePage />, clientManifest);
if (result.hasErrors) {
await reportBuildErrors(result.errors);
// Decide whether to fail build or use partial result
if (result.errors.some(e => e.critical)) {
throw new Error("Critical pre-render errors detected");
}
}Optimizing static rendering for large sites and complex components.
import { unstable_prerender } from "react-server-dom-webpack/static.node";
import pLimit from "p-limit";
// Limit concurrent pre-rendering operations
const limit = pLimit(4);
async function prerenderPages(pages, clientManifest) {
const tasks = pages.map(page =>
limit(async () => {
const result = unstable_prerender(
<Page {...page} />,
clientManifest,
{ identifierPrefix: `page-${page.id}-` }
);
await fs.writeFile(`./dist/${page.slug}.html`, result.prelude);
return { page: page.slug, success: true };
})
);
const results = await Promise.allSettled(tasks);
const successful = results.filter(r => r.status === "fulfilled").length;
const failed = results.filter(r => r.status === "rejected").length;
console.log(`Pre-rendered ${successful} pages, ${failed} failed`);
return results;
}// build/cache.js
import crypto from "crypto";
const prerenderCache = new Map();
function getCacheKey(component, manifest) {
const componentHash = crypto
.createHash("md5")
.update(JSON.stringify(component))
.digest("hex");
const manifestHash = crypto
.createHash("md5")
.update(JSON.stringify(manifest))
.digest("hex");
return `${componentHash}-${manifestHash}`;
}
async function cachedPrerender(component, clientManifest) {
const cacheKey = getCacheKey(component, clientManifest);
if (prerenderCache.has(cacheKey)) {
console.log("Cache hit for pre-render");
return prerenderCache.get(cacheKey);
}
const result = unstable_prerender(component, clientManifest);
prerenderCache.set(cacheKey, result);
return result;
}interface StaticResult {
/** ReadableStream containing pre-rendered content */
prelude: ReadableStream;
}
type ReactClientValue = any;
type ClientManifest = Record<string, ImportManifestEntry>;
interface ImportManifestEntry {
id: string;
chunks: string[];
name: string;
}Note: Static rendering functions use the same ServerOptions interface as documented in Server APIs.
Static rendering works best with proper Webpack configuration:
// webpack.static.config.js
module.exports = {
target: "node",
entry: "./build/static-generator.js",
plugins: [
new ReactFlightWebpackPlugin({
isServer: false,
clientReferences: ["./src/**/*.client.js"]
})
],
externals: {
// Externalize Node.js modules for static generation
"fs": "commonjs fs",
"path": "commonjs path"
}
};Integration with popular static site generators:
getStaticProps or build scriptscreatePages APIStatic pre-rendering provides:
Install with Tessl CLI
npx tessl i tessl/npm-react-server-dom-webpack