0
# Node.js Integration
1
2
Node.js-specific utilities for server component module loading, directive processing, and runtime integration with React Server Components.
3
4
## Capabilities
5
6
### Module Registration
7
8
Registers Node.js module compilation hooks to automatically process "use client" and "use server" directives during module loading.
9
10
```javascript { .api }
11
/**
12
* Registers Node.js module hooks for directive processing
13
* Hooks into the Node.js module system to handle RSC directives
14
*/
15
function register(): void;
16
```
17
18
**Usage Examples:**
19
20
```javascript
21
// Register hooks before importing any server components
22
const register = require("react-server-dom-webpack/node-register");
23
register();
24
25
// Now you can import modules with directives
26
const ServerComponent = require("./ServerComponent"); // Contains "use server"
27
const ClientComponent = require("./ClientComponent"); // Contains "use client"
28
```
29
30
**Package.json Integration:**
31
32
```json
33
{
34
"scripts": {
35
"dev": "node -r react-server-dom-webpack/node-register src/server.js",
36
"start": "node --require react-server-dom-webpack/node-register dist/server.js"
37
}
38
}
39
```
40
41
**Programmatic Registration:**
42
43
```javascript
44
// server.js
45
require("react-server-dom-webpack/node-register")();
46
47
// Import React Server Components after registration
48
const { renderToPipeableStream } = require("react-server-dom-webpack/server.node");
49
const App = require("./App"); // Can contain RSC directives
50
51
function handleRequest(req, res) {
52
const { pipe } = renderToPipeableStream(<App />, clientManifest);
53
pipe(res);
54
}
55
```
56
57
### Directive Processing
58
59
The registration system automatically processes modules containing RSC directives:
60
61
#### "use client" Directive Processing
62
63
Files with "use client" are converted to client module proxies:
64
65
```javascript
66
// components/Button.js
67
"use client";
68
69
import { useState } from "react";
70
71
export function Button({ children, onClick }) {
72
const [loading, setLoading] = useState(false);
73
// ... component implementation
74
}
75
76
// After processing, exports become client module proxies
77
// that reference the client-side bundle
78
```
79
80
#### "use server" Directive Processing
81
82
Files with "use server" have their functions registered as server references:
83
84
```javascript
85
// actions/userActions.js
86
"use server";
87
88
export async function updateUser(userData) {
89
// This function is registered as a server reference
90
return await database.users.update(userData);
91
}
92
93
export async function deleteUser(userId) {
94
// This function is also registered as a server reference
95
return await database.users.delete(userId);
96
}
97
98
// After processing, functions can be called from client components
99
```
100
101
### Module Loading Patterns
102
103
Different patterns for loading and using the registration system:
104
105
#### Early Registration Pattern
106
107
```javascript
108
// server/index.js
109
// Register before any imports
110
require("react-server-dom-webpack/node-register")();
111
112
// Safe to import RSC modules after registration
113
const express = require("express");
114
const { renderToPipeableStream } = require("react-server-dom-webpack/server.node");
115
const App = require("../components/App");
116
117
const app = express();
118
119
app.get("/", (req, res) => {
120
const { pipe } = renderToPipeableStream(<App />, clientManifest);
121
res.setHeader("Content-Type", "text/html");
122
pipe(res);
123
});
124
```
125
126
#### Conditional Registration Pattern
127
128
```javascript
129
// utils/setup.js
130
let registered = false;
131
132
function ensureRegistered() {
133
if (!registered) {
134
require("react-server-dom-webpack/node-register")();
135
registered = true;
136
}
137
}
138
139
module.exports = { ensureRegistered };
140
141
// Use in multiple entry points
142
const { ensureRegistered } = require("./utils/setup");
143
ensureRegistered();
144
```
145
146
#### Development vs Production Pattern
147
148
```javascript
149
// server/setup.js
150
if (process.env.NODE_ENV === "development") {
151
// Enable directive processing in development
152
require("react-server-dom-webpack/node-register")();
153
}
154
155
// In production, components are pre-processed during build
156
```
157
158
### Error Handling
159
160
The registration system provides comprehensive error handling for directive processing:
161
162
#### Conflicting Directives
163
164
```javascript
165
// This will throw an error
166
"use client";
167
"use server"; // Cannot have both directives
168
169
// Error message:
170
// "Cannot have both 'use client' and 'use server' directives in the same file."
171
```
172
173
#### Parse Errors
174
175
```javascript
176
// Malformed syntax in directive file
177
"use client";
178
export function Component() {
179
// Syntax error here
180
return <div>Hello</div>
181
}
182
183
// Error logged to console:
184
// "Error parsing [filename] [error message]"
185
```
186
187
### ESM Loader Integration
188
189
For ESM modules, use the dedicated loader instead of the CommonJS register:
190
191
```javascript
192
// package.json
193
{
194
"type": "module",
195
"scripts": {
196
"dev": "node --loader react-server-dom-webpack/node-loader src/server.js"
197
}
198
}
199
```
200
201
**ESM Server Setup:**
202
203
```javascript
204
// server.js (ESM)
205
import { renderToPipeableStream } from "react-server-dom-webpack/server.node";
206
import App from "./components/App.js";
207
208
// ESM loader automatically processes directives
209
export function handleRequest(req, res) {
210
const { pipe } = renderToPipeableStream(<App />, clientManifest);
211
pipe(res);
212
}
213
```
214
215
### Advanced Integration Patterns
216
217
#### Framework Integration
218
219
```javascript
220
// next.config.js (example integration)
221
module.exports = {
222
experimental: {
223
serverComponentsExternalPackages: ["react-server-dom-webpack"]
224
},
225
webpack: (config, { isServer }) => {
226
if (isServer) {
227
// Ensure registration happens in server environment
228
config.plugins.push({
229
apply(compiler) {
230
compiler.hooks.beforeRun.tap("RSCRegister", () => {
231
require("react-server-dom-webpack/node-register")();
232
});
233
}
234
});
235
}
236
return config;
237
}
238
};
239
```
240
241
#### Testing Integration
242
243
```javascript
244
// test/setup.js
245
const register = require("react-server-dom-webpack/node-register");
246
247
// Register before running tests
248
beforeAll(() => {
249
register();
250
});
251
252
// test/server-components.test.js
253
const ServerComponent = require("../components/ServerComponent");
254
255
test("server component renders correctly", async () => {
256
// ServerComponent contains "use server" directive
257
const result = await ServerComponent.someAction();
258
expect(result).toBeDefined();
259
});
260
```
261
262
#### Hot Reload Integration
263
264
```javascript
265
// dev-server.js
266
const chokidar = require("chokidar");
267
268
// Watch for changes and re-register
269
chokidar.watch("./src/**/*.js").on("change", (path) => {
270
// Clear module cache
271
delete require.cache[require.resolve(path)];
272
273
// Re-register to pick up directive changes
274
require("react-server-dom-webpack/node-register")();
275
});
276
```
277
278
### Performance Considerations
279
280
#### Module Caching
281
282
The registration system respects Node.js module caching:
283
284
```javascript
285
// First import processes and caches the module
286
const Component1 = require("./MyComponent");
287
288
// Second import uses cached result
289
const Component2 = require("./MyComponent"); // Same instance
290
```
291
292
#### Directive Detection Optimization
293
294
The system performs fast string checks before parsing:
295
296
```javascript
297
// Fast path: no parsing needed
298
if (content.indexOf('use client') === -1 && content.indexOf('use server') === -1) {
299
return originalCompile.apply(this, arguments);
300
}
301
302
// Only parse files that might contain directives
303
```
304
305
## Types
306
307
```javascript { .api }
308
// No exported types - register() is a side-effect function
309
// The registration affects the module loading behavior globally
310
311
interface ModuleCompilerHook {
312
/** Original Node.js module compilation function */
313
_compile(content: string, filename: string): void;
314
}
315
316
interface DirectiveInfo {
317
/** Whether file contains "use client" */
318
useClient: boolean;
319
/** Whether file contains "use server" */
320
useServer: boolean;
321
/** Parsed AST body for directive detection */
322
body: any[];
323
}
324
```
325
326
## Integration Notes
327
328
### Build vs Runtime
329
330
- **Development**: Use `node-register` for runtime directive processing
331
- **Production**: Pre-process directives during build for better performance
332
- **Testing**: Register hooks in test setup for consistent behavior
333
334
### Compatibility
335
336
- **CommonJS**: Use `require("react-server-dom-webpack/node-register")()`
337
- **ESM**: Use `--loader react-server-dom-webpack/node-loader`
338
- **Mixed**: Can use both in hybrid applications
339
340
### Debugging
341
342
Enable verbose logging for directive processing:
343
344
```javascript
345
// Set environment variable for debugging
346
process.env.DEBUG = "react-server-dom-webpack:*";
347
348
require("react-server-dom-webpack/node-register")();
349
```