or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-apis.mddata-communication.mdindex.mdnodejs-integration.mdserver-apis.mdstatic-rendering.mdwebpack-plugin.md

static-rendering.mddocs/

0

# Static Rendering

1

2

Static pre-rendering capabilities for React Server Components, enabling build-time generation of server component output for improved performance and SEO.

3

4

## Capabilities

5

6

### Unstable Prerender

7

8

Pre-renders React Server Components at build time, generating static output that can be served directly or hydrated on the client.

9

10

```javascript { .api }

11

/**

12

* Pre-renders server components for static generation

13

* @param model - React server component tree to pre-render

14

* @param webpackMap - Client manifest for module resolution

15

* @param options - Optional rendering configuration

16

* @returns Promise resolving to pre-render result

17

*/

18

function unstable_prerender(

19

model: ReactClientValue,

20

webpackMap: ClientManifest,

21

options?: ServerOptions

22

): Promise<StaticResult>;

23

```

24

25

**Usage Examples:**

26

27

```javascript

28

import { unstable_prerender } from "react-server-dom-webpack/static.browser";

29

30

// Pre-render a server component at build time

31

async function generateStaticPage() {

32

const clientManifest = JSON.parse(

33

await fs.readFile("./react-client-manifest.json", "utf8")

34

);

35

36

const result = unstable_prerender(

37

<HomePage posts={staticPosts} />,

38

clientManifest,

39

{

40

identifierPrefix: "static-",

41

onError: (error) => {

42

console.error("Static render error:", error);

43

}

44

}

45

);

46

47

// Save static output

48

await fs.writeFile("./dist/home.html", result.prelude);

49

return result;

50

}

51

52

// Build-time page generation

53

const pages = [

54

{ path: "/", component: <HomePage /> },

55

{ path: "/about", component: <AboutPage /> },

56

{ path: "/contact", component: <ContactPage /> }

57

];

58

59

for (const page of pages) {

60

const result = unstable_prerender(page.component, clientManifest);

61

await saveStaticPage(page.path, result);

62

}

63

```

64

65

### Node.js Pre-rendering

66

67

Node.js-specific pre-rendering with stream support for build pipelines.

68

69

```javascript { .api }

70

/**

71

* Pre-renders server components to Node.js stream for build tools

72

* @param model - React server component tree to pre-render

73

* @param webpackMap - Client manifest for module resolution

74

* @param options - Optional rendering configuration

75

* @returns ReadableStream containing pre-rendered content

76

*/

77

function unstable_prerenderToNodeStream(

78

model: ReactClientValue,

79

webpackMap: ClientManifest,

80

options?: ServerOptions

81

): ReadableStream;

82

```

83

84

**Usage Examples:**

85

86

```javascript

87

import { unstable_prerenderToNodeStream } from "react-server-dom-webpack/static.node";

88

import { createWriteStream } from "fs";

89

90

// Stream pre-rendered content to file

91

async function prerenderToFile(component, outputPath) {

92

const clientManifest = JSON.parse(

93

fs.readFileSync("./react-client-manifest.json", "utf8")

94

);

95

96

const stream = unstable_prerenderToNodeStream(

97

component,

98

clientManifest,

99

{

100

onError: (error) => console.error("Prerender error:", error),

101

signal: abortController.signal

102

}

103

);

104

105

const writeStream = createWriteStream(outputPath);

106

107

// Pipe pre-rendered output to file

108

stream.pipe(writeStream);

109

110

return new Promise((resolve, reject) => {

111

writeStream.on("finish", resolve);

112

writeStream.on("error", reject);

113

});

114

}

115

116

// Build-time static generation

117

await prerenderToFile(<BlogPost post={postData} />, "./dist/blog/post-123.html");

118

```

119

120

### Static Site Generation Patterns

121

122

Common patterns for integrating static pre-rendering into build workflows.

123

124

#### Build-Time Page Generation

125

126

```javascript

127

// build/generatePages.js

128

import { unstable_prerender } from "react-server-dom-webpack/static.node";

129

import { loadClientManifest, getAllPosts, getAllPages } from "./utils";

130

131

async function generateStaticSite() {

132

const clientManifest = await loadClientManifest();

133

const posts = await getAllPosts();

134

const pages = await getAllPages();

135

136

// Generate static pages

137

for (const page of pages) {

138

const result = unstable_prerender(

139

<Page {...page} />,

140

clientManifest,

141

{ identifierPrefix: `page-${page.id}-` }

142

);

143

144

await fs.writeFile(`./dist/${page.slug}.html`, result.prelude);

145

console.log(`Generated: ${page.slug}`);

146

}

147

148

// Generate blog posts

149

for (const post of posts) {

150

const result = unstable_prerender(

151

<BlogPost post={post} />,

152

clientManifest,

153

{ identifierPrefix: `post-${post.id}-` }

154

);

155

156

await fs.writeFile(`./dist/blog/${post.slug}.html`, result.prelude);

157

console.log(`Generated: blog/${post.slug}`);

158

}

159

}

160

161

generateStaticSite().catch(console.error);

162

```

163

164

#### Incremental Static Regeneration

165

166

```javascript

167

// api/revalidate.js

168

import { unstable_prerender } from "react-server-dom-webpack/static.browser";

169

170

export async function POST(request) {

171

const { path, data } = await request.json();

172

173

try {

174

// Re-generate specific page

175

const result = unstable_prerender(

176

<DynamicPage data={data} />,

177

clientManifest,

178

{

179

identifierPrefix: `revalidate-${Date.now()}-`,

180

onError: (error) => {

181

console.error(`Revalidation error for ${path}:`, error);

182

}

183

}

184

);

185

186

// Update static file

187

await fs.writeFile(`./dist${path}.html`, result.prelude);

188

189

return Response.json({ success: true, path });

190

} catch (error) {

191

return Response.json({ error: error.message }, { status: 500 });

192

}

193

}

194

```

195

196

#### Build Tool Integration

197

198

```javascript

199

// webpack.config.js

200

const ReactFlightWebpackPlugin = require("react-server-dom-webpack/plugin");

201

202

module.exports = {

203

plugins: [

204

new ReactFlightWebpackPlugin({

205

isServer: false,

206

clientReferences: ["./src/**/*.client.js"]

207

}),

208

209

// Custom plugin for static generation

210

{

211

apply(compiler) {

212

compiler.hooks.afterEmit.tapAsync("StaticGeneration", async (compilation, callback) => {

213

const { unstable_prerender } = require("react-server-dom-webpack/static.node");

214

215

// Generate static pages after build

216

await generateStaticPages(unstable_prerender);

217

callback();

218

});

219

}

220

}

221

]

222

};

223

```

224

225

### Pre-render Result Handling

226

227

Working with pre-render results and their metadata.

228

229

```javascript

230

// Handle pre-render result

231

const result = unstable_prerender(<App />, clientManifest);

232

233

// Extract different parts of the result

234

const {

235

prelude, // Static HTML content

236

postponed, // Postponed content for streaming

237

metadata // Additional rendering metadata

238

} = result;

239

240

// Save static content

241

await fs.writeFile("./static/app.html", prelude);

242

243

// Handle postponed content if any

244

if (postponed) {

245

await handlePostponedContent(postponed);

246

}

247

```

248

249

### Error Handling in Static Rendering

250

251

Comprehensive error handling for build-time rendering issues.

252

253

```javascript

254

import { unstable_prerender } from "react-server-dom-webpack/static.browser";

255

256

async function safePrerender(component, clientManifest, options = {}) {

257

const errors = [];

258

259

const result = unstable_prerender(

260

component,

261

clientManifest,

262

{

263

...options,

264

onError: (error) => {

265

errors.push({

266

message: error.message,

267

stack: error.stack,

268

timestamp: new Date().toISOString()

269

});

270

271

// Log error but continue rendering

272

console.error("Pre-render error:", error);

273

}

274

}

275

);

276

277

return {

278

...result,

279

errors,

280

hasErrors: errors.length > 0

281

};

282

}

283

284

// Use with error reporting

285

const result = await safePrerender(<HomePage />, clientManifest);

286

287

if (result.hasErrors) {

288

await reportBuildErrors(result.errors);

289

290

// Decide whether to fail build or use partial result

291

if (result.errors.some(e => e.critical)) {

292

throw new Error("Critical pre-render errors detected");

293

}

294

}

295

```

296

297

### Performance Optimization

298

299

Optimizing static rendering for large sites and complex components.

300

301

#### Parallel Pre-rendering

302

303

```javascript

304

import { unstable_prerender } from "react-server-dom-webpack/static.node";

305

import pLimit from "p-limit";

306

307

// Limit concurrent pre-rendering operations

308

const limit = pLimit(4);

309

310

async function prerenderPages(pages, clientManifest) {

311

const tasks = pages.map(page =>

312

limit(async () => {

313

const result = unstable_prerender(

314

<Page {...page} />,

315

clientManifest,

316

{ identifierPrefix: `page-${page.id}-` }

317

);

318

319

await fs.writeFile(`./dist/${page.slug}.html`, result.prelude);

320

return { page: page.slug, success: true };

321

})

322

);

323

324

const results = await Promise.allSettled(tasks);

325

326

const successful = results.filter(r => r.status === "fulfilled").length;

327

const failed = results.filter(r => r.status === "rejected").length;

328

329

console.log(`Pre-rendered ${successful} pages, ${failed} failed`);

330

331

return results;

332

}

333

```

334

335

#### Caching Pre-rendered Content

336

337

```javascript

338

// build/cache.js

339

import crypto from "crypto";

340

341

const prerenderCache = new Map();

342

343

function getCacheKey(component, manifest) {

344

const componentHash = crypto

345

.createHash("md5")

346

.update(JSON.stringify(component))

347

.digest("hex");

348

349

const manifestHash = crypto

350

.createHash("md5")

351

.update(JSON.stringify(manifest))

352

.digest("hex");

353

354

return `${componentHash}-${manifestHash}`;

355

}

356

357

async function cachedPrerender(component, clientManifest) {

358

const cacheKey = getCacheKey(component, clientManifest);

359

360

if (prerenderCache.has(cacheKey)) {

361

console.log("Cache hit for pre-render");

362

return prerenderCache.get(cacheKey);

363

}

364

365

const result = unstable_prerender(component, clientManifest);

366

prerenderCache.set(cacheKey, result);

367

368

return result;

369

}

370

```

371

372

## Types

373

374

```javascript { .api }

375

interface StaticResult {

376

/** ReadableStream containing pre-rendered content */

377

prelude: ReadableStream;

378

}

379

380

type ReactClientValue = any;

381

type ClientManifest = Record<string, ImportManifestEntry>;

382

383

interface ImportManifestEntry {

384

id: string;

385

chunks: string[];

386

name: string;

387

}

388

```

389

390

**Note:** Static rendering functions use the same `ServerOptions` interface as documented in [Server APIs](./server-apis.md).

391

392

## Build Integration Notes

393

394

### Webpack Integration

395

396

Static rendering works best with proper Webpack configuration:

397

398

```javascript

399

// webpack.static.config.js

400

module.exports = {

401

target: "node",

402

entry: "./build/static-generator.js",

403

plugins: [

404

new ReactFlightWebpackPlugin({

405

isServer: false,

406

clientReferences: ["./src/**/*.client.js"]

407

})

408

],

409

externals: {

410

// Externalize Node.js modules for static generation

411

"fs": "commonjs fs",

412

"path": "commonjs path"

413

}

414

};

415

```

416

417

### Framework Integration

418

419

Integration with popular static site generators:

420

421

- **Next.js**: Use in `getStaticProps` or build scripts

422

- **Gatsby**: Integrate with `createPages` API

423

- **Vite**: Use in build plugins or custom generators

424

- **Custom**: Create build-time generation scripts

425

426

### SEO and Performance

427

428

Static pre-rendering provides:

429

430

- **Improved SEO**: Search engines can crawl static HTML

431

- **Faster Initial Load**: No client-side rendering delay

432

- **Better Core Web Vitals**: Reduced Time to First Byte

433

- **Progressive Enhancement**: Works without JavaScript