rsbuild-plugin-react-router 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +185 -204
- package/dist/451.js +1087 -0
- package/dist/bounded-cache.d.ts +1 -0
- package/dist/build-manifest.d.ts +1 -1
- package/dist/build-output-transforms.d.ts +30 -0
- package/dist/concurrency.d.ts +2 -0
- package/dist/config-imports.d.ts +3 -0
- package/dist/constants.d.ts +3 -0
- package/dist/dev-generation.d.ts +25 -0
- package/dist/dev-runtime-artifacts.d.ts +39 -0
- package/dist/dev-runtime-compilation.d.ts +32 -0
- package/dist/dev-runtime-controller.d.ts +14 -0
- package/dist/dev-runtime-session.d.ts +34 -0
- package/dist/dev-server.d.ts +11 -2
- package/dist/export-utils.d.ts +15 -7
- package/dist/index.cjs +3085 -1272
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2039 -1299
- package/dist/lazy-compilation.d.ts +5 -0
- package/dist/manifest.d.ts +32 -9
- package/dist/modify-browser-manifest.d.ts +30 -13
- package/dist/parallel-route-transform-protocol.d.ts +25 -0
- package/dist/parallel-route-transform-worker.d.ts +1 -0
- package/dist/parallel-route-transform-worker.js +38 -0
- package/dist/parallel-route-transforms.d.ts +14 -0
- package/dist/performance.d.ts +26 -0
- package/dist/plugin-utils.d.ts +2 -12
- package/dist/prerender-build.d.ts +32 -0
- package/dist/prerender.d.ts +28 -2
- package/dist/react-router-config.d.ts +8 -1
- package/dist/route-artifacts.d.ts +33 -0
- package/dist/route-ast.d.ts +21 -0
- package/dist/route-chunks.d.ts +9 -1
- package/dist/route-component-transform.d.ts +5 -0
- package/dist/route-export-pruning.d.ts +6 -0
- package/dist/route-export-resolution.d.ts +5 -0
- package/dist/route-transform-tasks.d.ts +47 -0
- package/dist/route-watch.d.ts +27 -0
- package/dist/server-build-plan.d.ts +22 -0
- package/dist/server-utils.d.ts +3 -2
- package/dist/templates/entry.client.js +3 -3
- package/dist/templates/entry.server.cjs +11 -8
- package/dist/templates/entry.server.js +5 -5
- package/dist/typegen.d.ts +2 -0
- package/dist/types.d.ts +30 -12
- package/dist/virtual-modules.d.ts +2 -0
- package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
- package/dist/yuku.d.ts +15 -0
- package/package.json +26 -22
- package/src/bounded-cache.ts +18 -0
- package/src/build-manifest.ts +168 -0
- package/src/build-output-transforms.ts +273 -0
- package/src/concurrency.ts +34 -0
- package/src/config-imports.ts +45 -0
- package/src/constants.ts +91 -0
- package/src/dev-generation.ts +700 -0
- package/src/dev-runtime-artifacts.ts +207 -0
- package/src/dev-runtime-compilation.ts +92 -0
- package/src/dev-runtime-controller.ts +462 -0
- package/src/dev-runtime-session.ts +184 -0
- package/src/dev-server.ts +58 -0
- package/src/export-utils.ts +219 -0
- package/src/index.ts +1025 -0
- package/src/lazy-compilation.ts +94 -0
- package/src/manifest.ts +480 -0
- package/src/modify-browser-manifest.ts +245 -0
- package/src/parallel-route-transform-protocol.ts +35 -0
- package/src/parallel-route-transform-worker.ts +82 -0
- package/src/parallel-route-transforms.ts +332 -0
- package/src/performance.ts +254 -0
- package/src/plugin-utils.ts +82 -0
- package/src/prerender-build.ts +623 -0
- package/src/prerender.ts +367 -0
- package/src/react-router-config.ts +220 -0
- package/src/route-artifacts.ts +155 -0
- package/src/route-ast.ts +163 -0
- package/src/route-chunks.ts +857 -0
- package/src/route-component-transform.ts +314 -0
- package/src/route-config.ts +106 -0
- package/src/route-export-pruning.ts +668 -0
- package/src/route-export-resolution.ts +329 -0
- package/src/route-transform-tasks.ts +249 -0
- package/src/route-watch.ts +322 -0
- package/src/server-build-plan.ts +91 -0
- package/src/server-utils.ts +210 -0
- package/src/ssr-externals.ts +59 -0
- package/src/templates/context.ts +12 -0
- package/src/templates/entry.client.tsx +12 -0
- package/src/templates/entry.server.tsx +76 -0
- package/src/typegen.ts +49 -0
- package/src/types.ts +82 -0
- package/src/validation/validate-plugin-order.ts +76 -0
- package/src/virtual-modules.ts +30 -0
- package/src/warnings/warn-on-client-source-maps.ts +96 -0
- package/src/yuku.ts +67 -0
- package/dist/906.js +0 -1
- package/dist/946.js +0 -1
- package/dist/babel.d.ts +0 -8
- package/dist/rslib-runtime.js +0 -23
package/README.md
CHANGED
|
@@ -8,7 +8,6 @@ A Rsbuild plugin that provides seamless integration with React Router, supportin
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
- 🚀 Zero-config setup with sensible defaults
|
|
13
12
|
- 🔄 Automatic route generation from file system
|
|
14
13
|
- 🖥️ Server-Side Rendering (SSR) support
|
|
@@ -48,128 +47,86 @@ Add the plugin to your `rsbuild.config.ts`:
|
|
|
48
47
|
|
|
49
48
|
```ts
|
|
50
49
|
import { defineConfig } from '@rsbuild/core';
|
|
51
|
-
import { pluginReactRouter } from 'rsbuild-plugin-react-router';
|
|
52
50
|
import { pluginReact } from '@rsbuild/plugin-react';
|
|
51
|
+
import { pluginReactRouter } from 'rsbuild-plugin-react-router';
|
|
53
52
|
|
|
54
|
-
export default defineConfig(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
serverOutput: "commonjs",
|
|
62
|
-
// Optional: enable experimental support for module federation
|
|
63
|
-
federation: false
|
|
64
|
-
}),
|
|
65
|
-
pluginReact()
|
|
66
|
-
],
|
|
67
|
-
};
|
|
53
|
+
export default defineConfig({
|
|
54
|
+
plugins: [
|
|
55
|
+
pluginReactRouter({
|
|
56
|
+
// options here
|
|
57
|
+
}),
|
|
58
|
+
pluginReact(),
|
|
59
|
+
],
|
|
68
60
|
});
|
|
69
61
|
```
|
|
70
62
|
|
|
71
63
|
## Configuration
|
|
72
64
|
|
|
73
|
-
|
|
65
|
+
React Router application settings live in `react-router.config.*`. The Rsbuild
|
|
66
|
+
plugin only needs options for Rsbuild-specific behavior.
|
|
67
|
+
|
|
68
|
+
### Plugin Options
|
|
74
69
|
|
|
75
|
-
1. **Plugin Options** (in `rsbuild.config.ts`):
|
|
76
70
|
```ts
|
|
77
71
|
pluginReactRouter({
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
* Specify the output format for server-side code.
|
|
87
|
-
* Options: "commonjs" | "module"
|
|
88
|
-
* @default "module"
|
|
89
|
-
*/
|
|
90
|
-
serverOutput?: "commonjs" | "module"
|
|
91
|
-
/**
|
|
92
|
-
* Enable experimental support for module federation
|
|
93
|
-
* @default false
|
|
94
|
-
*/
|
|
95
|
-
federation?: boolean
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
When Module Federation is enabled, configure your Federation plugin with
|
|
99
|
-
`experiments.asyncStartup: true` to avoid requiring entrypoint `import()` hacks.
|
|
100
|
-
See the Module Federation examples under `examples/federation`.
|
|
101
|
-
|
|
102
|
-
When Module Federation is enabled, some runtimes may expose server build exports
|
|
103
|
-
as async getters. The dev server resolves these exports automatically. For
|
|
104
|
-
production, use a custom server or an adapter that resolves async exports before
|
|
105
|
-
passing the build to React Router's request handler.
|
|
72
|
+
customServer: false,
|
|
73
|
+
serverOutput: 'module',
|
|
74
|
+
lazyCompilation: undefined,
|
|
75
|
+
logPerformance: false,
|
|
76
|
+
parallelRouteTransform: undefined,
|
|
77
|
+
onRouteTopologyChange: undefined,
|
|
78
|
+
federation: false,
|
|
79
|
+
});
|
|
106
80
|
```
|
|
107
81
|
|
|
108
|
-
|
|
82
|
+
| Option | Default | Description |
|
|
83
|
+
| ------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `customServer` | `false` | Disables the built-in development SSR middleware. Enable this when an app owns the server with `createDevServer()` or an adapter. |
|
|
85
|
+
| `serverOutput` | `'module'` | Emitted Rsbuild server format: `'module'` or `'commonjs'`. When omitted, React Router's `serverModuleFormat` selects the format (`'esm'` -> `'module'`, `'cjs'` -> `'commonjs'`); setting `serverOutput` overrides it. |
|
|
86
|
+
| `lazyCompilation` | `undefined` | Optional Rsbuild dev lazy-compilation config. When enabled here or through `dev.lazyCompilation`, React Router hydration-critical modules stay eager so the browser manifest and route modules are not replaced by lazy proxies. |
|
|
87
|
+
| `logPerformance` | `false` | Logs structured React Router plugin timing information through the Rsbuild logger. |
|
|
88
|
+
| `parallelRouteTransform` | `undefined` | Controls worker-thread route transforms. `undefined` auto-enables workers for 256+ routes, `true` forces the default worker count, a positive integer sets the worker count, and `false` keeps transforms inline. |
|
|
89
|
+
| `onRouteTopologyChange` | `undefined` | Notification for programmatic/custom dev servers. Recreate the Rsbuild server when route files are added, removed, or moved. The callback is not awaited. |
|
|
90
|
+
| `federation` | `false` | Enables the plugin's experimental Module Federation integration. |
|
|
91
|
+
|
|
92
|
+
When `federation` is enabled, configure the Module Federation plugin with
|
|
93
|
+
`experiments.asyncStartup: true`. The dev server resolves async server build
|
|
94
|
+
exports automatically; production custom servers or adapters should resolve
|
|
95
|
+
async exports before passing the build to React Router's request handler.
|
|
96
|
+
|
|
97
|
+
### React Router Config
|
|
98
|
+
|
|
99
|
+
Put React Router framework settings in `react-router.config.*`:
|
|
100
|
+
|
|
109
101
|
```ts
|
|
110
102
|
import type { Config } from '@react-router/dev/config';
|
|
111
103
|
|
|
112
104
|
export default {
|
|
113
|
-
/**
|
|
114
|
-
* Whether to enable Server-Side Rendering (SSR) support.
|
|
115
|
-
* @default true
|
|
116
|
-
*/
|
|
117
105
|
ssr: true,
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* The file name for the server build output.
|
|
121
|
-
* @default "index.js"
|
|
122
|
-
*/
|
|
123
|
-
serverBuildFile: "index.js",
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* The output format for the server build.
|
|
127
|
-
* Options: "esm" | "cjs"
|
|
128
|
-
* @default "esm"
|
|
129
|
-
*/
|
|
130
|
-
serverModuleFormat: "esm",
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Split server bundles by route branch (advanced).
|
|
134
|
-
*/
|
|
135
|
-
serverBundles: async ({ branch }) => branch[0]?.id ?? "main",
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Hook called after the build completes.
|
|
139
|
-
*/
|
|
140
|
-
buildEnd: async ({ buildManifest, reactRouterConfig }) => {
|
|
141
|
-
console.log(buildManifest, reactRouterConfig);
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Build directory for output files
|
|
146
|
-
* @default 'build'
|
|
147
|
-
*/
|
|
148
|
-
buildDirectory: 'dist',
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Application source directory
|
|
152
|
-
* @default 'app'
|
|
153
|
-
*/
|
|
106
|
+
buildDirectory: 'build',
|
|
154
107
|
appDirectory: 'app',
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
* @default '/'
|
|
159
|
-
*/
|
|
160
|
-
basename: '/my-app',
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* React Router future flags (optional).
|
|
164
|
-
* Example: split client route modules into separate chunks.
|
|
165
|
-
*/
|
|
166
|
-
future: {
|
|
167
|
-
v8_splitRouteModules: true,
|
|
168
|
-
},
|
|
108
|
+
basename: '/',
|
|
109
|
+
splitRouteModules: true,
|
|
110
|
+
subResourceIntegrity: false,
|
|
169
111
|
} satisfies Config;
|
|
170
112
|
```
|
|
171
113
|
|
|
172
|
-
|
|
114
|
+
Commonly used options:
|
|
115
|
+
|
|
116
|
+
| Option | Default | Notes |
|
|
117
|
+
| ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `ssr` | `true` | Set `false` for SPA mode. SPA mode still runs a build-time server render to create `build/client/index.html`. |
|
|
119
|
+
| `buildDirectory` | `'build'` | Output root. Client assets go in `<buildDirectory>/client`; server output goes in `<buildDirectory>/server`. |
|
|
120
|
+
| `appDirectory` | `'app'` | Directory containing `root`, `routes`, and optional `entry.client` / `entry.server` files. |
|
|
121
|
+
| `basename` | `'/'` | Base URL used for routing, prerender requests, and manifest asset paths. |
|
|
122
|
+
| `serverBuildFile` | `'index.js'` | Server build file name. It must end in `.js`. |
|
|
123
|
+
| `serverModuleFormat` | `'esm'` | React Router server module format: `'esm'` or `'cjs'`. `serverOutput` can override the emitted Rsbuild server format. |
|
|
124
|
+
| `serverBundles` | `undefined` | Advanced server bundle splitting by route branch. Disabled when `ssr: false`. |
|
|
125
|
+
| `routeDiscovery` | React Router | Defaults to lazy discovery for SSR and initial discovery for SPA mode. `routeDiscovery.mode: 'lazy'` is invalid for SPA. |
|
|
126
|
+
| `prerender` | `undefined` | `true`, an array of paths, a function, or `{ paths, concurrency }` / `{ paths, unstable_concurrency }`. |
|
|
127
|
+
| `splitRouteModules` | `true` | Splits client route module exports. The legacy `future.v8_splitRouteModules` flag is also accepted. |
|
|
128
|
+
| `subResourceIntegrity` | `false` | Emits SRI metadata for browser scripts. The legacy `future.unstable_subResourceIntegrity` flag is normalized to this key. |
|
|
129
|
+
| `buildEnd` | `undefined` | Hook called after the build with the React Router build manifest and resolved config. |
|
|
173
130
|
|
|
174
131
|
### Config File Resolution
|
|
175
132
|
|
|
@@ -256,36 +213,27 @@ export default {
|
|
|
256
213
|
} satisfies Config;
|
|
257
214
|
```
|
|
258
215
|
|
|
259
|
-
|
|
216
|
+
Prerendering defaults to one path at a time, matching React Router. Use
|
|
217
|
+
`concurrency` for larger sites; `unstable_concurrency` is still accepted for
|
|
218
|
+
older configs:
|
|
260
219
|
|
|
261
220
|
```ts
|
|
262
221
|
export default {
|
|
263
222
|
ssr: false,
|
|
264
223
|
prerender: {
|
|
265
|
-
paths: ['/','/about'],
|
|
266
|
-
|
|
224
|
+
paths: ['/', '/about'],
|
|
225
|
+
concurrency: 4,
|
|
267
226
|
},
|
|
268
227
|
} satisfies Config;
|
|
269
228
|
```
|
|
270
229
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
230
|
+
For builds with 256+ routes, detailed file-size reporting is compacted to totals
|
|
231
|
+
by default to avoid gzipping and printing thousands of assets. Set
|
|
232
|
+
`performance.printFileSize` to an object to customize that output.
|
|
274
233
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
{
|
|
278
|
-
customServer: false
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Router defaults (react-router.config.ts)
|
|
282
|
-
{
|
|
283
|
-
ssr: true,
|
|
284
|
-
buildDirectory: 'build',
|
|
285
|
-
appDirectory: 'app',
|
|
286
|
-
basename: '/'
|
|
287
|
-
}
|
|
288
|
-
```
|
|
234
|
+
Route transform source maps are generated in development only. If you enable
|
|
235
|
+
Rsbuild source maps for faster local debugging, prefer a cheap JS map:
|
|
236
|
+
`output.sourceMap: { js: 'cheap-module-source-map', css: false }`.
|
|
289
237
|
|
|
290
238
|
### Route Configuration
|
|
291
239
|
|
|
@@ -326,6 +274,7 @@ export default [
|
|
|
326
274
|
```
|
|
327
275
|
|
|
328
276
|
The plugin provides several helper functions for defining routes:
|
|
277
|
+
|
|
329
278
|
- `index()` - Creates an index route
|
|
330
279
|
- `route()` - Creates a regular route with a path
|
|
331
280
|
- `layout()` - Creates a layout route with nested children
|
|
@@ -336,6 +285,7 @@ The plugin provides several helper functions for defining routes:
|
|
|
336
285
|
Route components support the following exports:
|
|
337
286
|
|
|
338
287
|
#### Client-side Exports
|
|
288
|
+
|
|
339
289
|
- `default` - The route component
|
|
340
290
|
- `ErrorBoundary` - Error boundary component
|
|
341
291
|
- `HydrateFallback` - Loading component during hydration
|
|
@@ -349,6 +299,7 @@ Route components support the following exports:
|
|
|
349
299
|
- `shouldRevalidate` - Revalidation control
|
|
350
300
|
|
|
351
301
|
#### Server-side Exports
|
|
302
|
+
|
|
352
303
|
- `loader` - Server-side data loading
|
|
353
304
|
- `action` - Server-side form actions
|
|
354
305
|
- `middleware` - Server-side middleware
|
|
@@ -387,34 +338,37 @@ export default defineConfig(() => {
|
|
|
387
338
|
return {
|
|
388
339
|
plugins: [
|
|
389
340
|
pluginReactRouter({
|
|
390
|
-
customServer: true
|
|
391
|
-
}),
|
|
392
|
-
pluginReact()
|
|
341
|
+
customServer: true,
|
|
342
|
+
}),
|
|
343
|
+
pluginReact(),
|
|
393
344
|
],
|
|
394
345
|
};
|
|
395
346
|
});
|
|
396
347
|
```
|
|
397
348
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
```
|
|
349
|
+
If the server is created programmatically with `createDevServer()`, pass
|
|
350
|
+
`onRouteTopologyChange` and use it to recreate that server. Rsbuild's
|
|
351
|
+
`reload-server` watcher is owned by the CLI and is not installed by the
|
|
352
|
+
programmatic API. The callback is a notification and is not awaited, so it can
|
|
353
|
+
safely start a serialized replacement task. Always `await` the active server's
|
|
354
|
+
`close()` before calling `createDevServer()` again; the plugin rejects overlapping
|
|
355
|
+
or out-of-order replacement instead of closing one server from inside another
|
|
356
|
+
server's startup hooks. If startup fails before returning a server, or if
|
|
357
|
+
`close()` rejects, restart the process before retrying unless you can externally
|
|
358
|
+
prove and force complete teardown; a fresh Rsbuild instance alone is not
|
|
359
|
+
sufficient. Do not launch concurrent `createDevServer()` calls.
|
|
360
|
+
|
|
361
|
+
Create one server entry point (`server.js`) and let it own the React Router
|
|
362
|
+
request handler in both development and production. Only the build provider
|
|
363
|
+
changes between modes:
|
|
414
364
|
|
|
415
|
-
2. Set up your server entry point (`server.js`):
|
|
416
365
|
```js
|
|
417
366
|
import { createRsbuild, loadConfig } from '@rsbuild/core';
|
|
367
|
+
import { createRequestHandler } from '@react-router/express';
|
|
368
|
+
import {
|
|
369
|
+
loadReactRouterServerBuild,
|
|
370
|
+
resolveReactRouterServerBuild,
|
|
371
|
+
} from 'rsbuild-plugin-react-router';
|
|
418
372
|
import express from 'express';
|
|
419
373
|
import path from 'path';
|
|
420
374
|
import { fileURLToPath } from 'url';
|
|
@@ -426,80 +380,95 @@ const app = express();
|
|
|
426
380
|
const isDev = process.env.NODE_ENV !== 'production';
|
|
427
381
|
|
|
428
382
|
async function startServer() {
|
|
383
|
+
let devServer;
|
|
384
|
+
let build;
|
|
385
|
+
|
|
429
386
|
if (isDev) {
|
|
430
387
|
const config = await loadConfig();
|
|
431
388
|
const rsbuild = await createRsbuild({
|
|
432
389
|
rsbuildConfig: config.content,
|
|
433
390
|
});
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
try {
|
|
439
|
-
const bundle = await devServer.environments.node.loadBundle('app');
|
|
440
|
-
await bundle.app(req, res, next);
|
|
441
|
-
} catch (e) {
|
|
442
|
-
next(e);
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
const port = Number.parseInt(process.env.PORT || '3000', 10);
|
|
447
|
-
const server = app.listen(port, () => {
|
|
448
|
-
console.log(`Development server is running on http://localhost:${port}`);
|
|
449
|
-
devServer.afterListen();
|
|
450
|
-
});
|
|
451
|
-
devServer.connectWebSocket({ server });
|
|
391
|
+
const currentDevServer = await rsbuild.createDevServer();
|
|
392
|
+
devServer = currentDevServer;
|
|
393
|
+
app.use(currentDevServer.middlewares);
|
|
394
|
+
build = () => loadReactRouterServerBuild(currentDevServer);
|
|
452
395
|
} else {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
app.use(async (req, res, next) => {
|
|
462
|
-
try {
|
|
463
|
-
await serverBundle.default.app(req, res, next);
|
|
464
|
-
} catch (e) {
|
|
465
|
-
next(e);
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
const port = Number.parseInt(process.env.PORT || '3000', 10);
|
|
470
|
-
app.listen(port, () => {
|
|
471
|
-
console.log(`Production server is running on http://localhost:${port}`);
|
|
472
|
-
});
|
|
396
|
+
app.use(
|
|
397
|
+
express.static(path.join(__dirname, 'build/client'), {
|
|
398
|
+
index: false,
|
|
399
|
+
})
|
|
400
|
+
);
|
|
401
|
+
build = await resolveReactRouterServerBuild(
|
|
402
|
+
import('./build/server/static/js/app.js')
|
|
403
|
+
);
|
|
473
404
|
}
|
|
405
|
+
|
|
406
|
+
app.use(
|
|
407
|
+
createRequestHandler({
|
|
408
|
+
build,
|
|
409
|
+
mode: isDev ? 'development' : 'production',
|
|
410
|
+
getLoadContext() {
|
|
411
|
+
return {
|
|
412
|
+
// Add custom loader/action context here.
|
|
413
|
+
};
|
|
414
|
+
},
|
|
415
|
+
})
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
const port = Number.parseInt(process.env.PORT || '3000', 10);
|
|
419
|
+
const server = app.listen(port, () => {
|
|
420
|
+
const mode = isDev ? 'Development' : 'Production';
|
|
421
|
+
console.log(`${mode} server is running on http://localhost:${port}`);
|
|
422
|
+
devServer?.afterListen();
|
|
423
|
+
});
|
|
424
|
+
devServer?.connectWebSocket({ server });
|
|
474
425
|
}
|
|
475
426
|
|
|
476
427
|
startServer().catch(console.error);
|
|
477
428
|
```
|
|
478
429
|
|
|
479
|
-
|
|
430
|
+
`loadReactRouterServerBuild` waits for a complete React Router development
|
|
431
|
+
generation. During rebuilds it returns the last successfully evaluated server
|
|
432
|
+
build, whose embedded manifest is paired with the selected web compilation.
|
|
433
|
+
A failed or incomplete candidate does not replace that last-good pair. The
|
|
434
|
+
built-in development middleware uses the same path. Calling
|
|
435
|
+
`devServer.environments.node.loadBundle()` directly bypasses this guarantee.
|
|
436
|
+
|
|
437
|
+
When `serverBundles` is configured, pass its exact Rsbuild entry name as the
|
|
438
|
+
optional second argument (for example, `bundle-a/index`). The default build
|
|
439
|
+
and every configured bundle are
|
|
440
|
+
evaluated and published as one generation; one failing bundle keeps the whole
|
|
441
|
+
previous generation active.
|
|
442
|
+
|
|
443
|
+
`resolveReactRouterServerBuild` accepts an imported production server module,
|
|
444
|
+
normalizes ESM and CommonJS namespace shapes, resolves supported asynchronous
|
|
445
|
+
build exports, and validates the result before it reaches React Router.
|
|
446
|
+
|
|
447
|
+
This guarantee covers the eagerly evaluated server entry object and its
|
|
448
|
+
embedded manifest. It does not snapshot deferred server chunks, make emitted
|
|
449
|
+
client assets immutable, or delay Rsbuild's WebSocket success notification.
|
|
450
|
+
Same-path server or client chunks can change before the matching framework
|
|
451
|
+
generation commits. Closing that publication gap requires a supported Rsbuild
|
|
452
|
+
graph-settled hook plus immutable or staged outputs.
|
|
453
|
+
|
|
454
|
+
Then update your `package.json` scripts:
|
|
455
|
+
|
|
480
456
|
```json
|
|
481
457
|
{
|
|
482
458
|
"scripts": {
|
|
483
|
-
"dev": "node server.js",
|
|
459
|
+
"dev": "NODE_ENV=development NODE_OPTIONS=\"--experimental-vm-modules\" node server.js",
|
|
484
460
|
"build": "rsbuild build",
|
|
485
461
|
"start": "NODE_ENV=production node server.js"
|
|
486
462
|
}
|
|
487
463
|
}
|
|
488
464
|
```
|
|
489
465
|
|
|
490
|
-
The custom server setup allows you to:
|
|
491
|
-
- Add custom middleware
|
|
492
|
-
- Handle API routes
|
|
493
|
-
- Integrate with databases
|
|
494
|
-
- Implement custom authentication
|
|
495
|
-
- Add server-side caching
|
|
496
|
-
- And more!
|
|
497
|
-
|
|
498
466
|
## Cloudflare Workers Deployment
|
|
499
467
|
|
|
500
468
|
To deploy your React Router app to Cloudflare Workers:
|
|
501
469
|
|
|
502
470
|
1. **Configure Rsbuild** (`rsbuild.config.ts`):
|
|
471
|
+
|
|
503
472
|
```ts
|
|
504
473
|
import { defineConfig } from '@rsbuild/core';
|
|
505
474
|
import { pluginReact } from '@rsbuild/plugin-react';
|
|
@@ -524,17 +493,24 @@ export default defineConfig({
|
|
|
524
493
|
module: true,
|
|
525
494
|
},
|
|
526
495
|
resolve: {
|
|
527
|
-
conditionNames: [
|
|
496
|
+
conditionNames: [
|
|
497
|
+
'workerd',
|
|
498
|
+
'worker',
|
|
499
|
+
'browser',
|
|
500
|
+
'import',
|
|
501
|
+
'require',
|
|
502
|
+
],
|
|
528
503
|
},
|
|
529
504
|
},
|
|
530
505
|
},
|
|
531
506
|
},
|
|
532
507
|
},
|
|
533
|
-
plugins: [pluginReactRouter({customServer: true}), pluginReact()],
|
|
508
|
+
plugins: [pluginReactRouter({ customServer: true }), pluginReact()],
|
|
534
509
|
});
|
|
535
510
|
```
|
|
536
511
|
|
|
537
512
|
2. **Configure Wrangler** (`wrangler.toml`):
|
|
513
|
+
|
|
538
514
|
```toml
|
|
539
515
|
workers_dev = true
|
|
540
516
|
name = "my-react-router-worker"
|
|
@@ -552,6 +528,7 @@ VALUE_FROM_CLOUDFLARE = "Hello from Cloudflare"
|
|
|
552
528
|
```
|
|
553
529
|
|
|
554
530
|
3. **Create Worker Entry** (`server/index.ts`):
|
|
531
|
+
|
|
555
532
|
```ts
|
|
556
533
|
import { createRequestHandler } from 'react-router';
|
|
557
534
|
|
|
@@ -588,6 +565,7 @@ export default {
|
|
|
588
565
|
```
|
|
589
566
|
|
|
590
567
|
4. **Update Package Dependencies**:
|
|
568
|
+
|
|
591
569
|
```json
|
|
592
570
|
{
|
|
593
571
|
"dependencies": {
|
|
@@ -605,6 +583,7 @@ export default {
|
|
|
605
583
|
```
|
|
606
584
|
|
|
607
585
|
5. **Setup Deployment Scripts** (`package.json`):
|
|
586
|
+
|
|
608
587
|
```json
|
|
609
588
|
{
|
|
610
589
|
"scripts": {
|
|
@@ -630,6 +609,7 @@ export default {
|
|
|
630
609
|
### Development Workflow:
|
|
631
610
|
|
|
632
611
|
1. Local Development:
|
|
612
|
+
|
|
633
613
|
```bash
|
|
634
614
|
# Start local development server
|
|
635
615
|
npm run dev
|
|
@@ -646,6 +626,7 @@ export default {
|
|
|
646
626
|
## Development
|
|
647
627
|
|
|
648
628
|
The plugin automatically:
|
|
629
|
+
|
|
649
630
|
- Runs type generation during development and build
|
|
650
631
|
- Sets up development server with live reload
|
|
651
632
|
- Handles route-based code splitting
|
|
@@ -657,7 +638,7 @@ React Router "Framework Mode" wraps Data Mode using a Vite plugin. This Rsbuild
|
|
|
657
638
|
plugin aims to match the important behaviors without depending on Vite:
|
|
658
639
|
|
|
659
640
|
- Typegen + Route Module API types (`./+types/*`)
|
|
660
|
-
- Route module splitting (`
|
|
641
|
+
- Route module splitting (`splitRouteModules`)
|
|
661
642
|
- SPA mode (`ssr: false`), SSR mode, and static prerendering (`prerender`)
|
|
662
643
|
|
|
663
644
|
Some Vite-specific integrations (for example Vite's environment API + critical
|
|
@@ -667,17 +648,17 @@ CSS endpoint) are not supported 1:1.
|
|
|
667
648
|
|
|
668
649
|
The repository includes several examples demonstrating different use cases:
|
|
669
650
|
|
|
670
|
-
| Example
|
|
671
|
-
|
|
672
|
-
| [default-template](./examples/default-template)
|
|
673
|
-
| [spa-mode](./examples/spa-mode)
|
|
674
|
-
| [prerender](./examples/prerender)
|
|
675
|
-
| [custom-node-server](./examples/custom-node-server)
|
|
676
|
-
| [cloudflare](./examples/cloudflare)
|
|
677
|
-
| [client-only](./examples/client-only)
|
|
678
|
-
| [epic-stack](./examples/epic-stack)
|
|
679
|
-
| [federation/epic-stack](./examples/federation/epic-stack)
|
|
680
|
-
| [federation/epic-stack-remote](./examples/federation/epic-stack-remote) | Module Federation remote
|
|
651
|
+
| Example | Description | Port | Command |
|
|
652
|
+
| ----------------------------------------------------------------------- | --------------------------------------- | ---- | ---------- |
|
|
653
|
+
| [default-template](./examples/default-template) | Standard SSR setup with React Router | 3000 | `pnpm dev` |
|
|
654
|
+
| [spa-mode](./examples/spa-mode) | Single Page Application (`ssr: false`) | 3001 | `pnpm dev` |
|
|
655
|
+
| [prerender](./examples/prerender) | Static prerendering for multiple routes | 3002 | `pnpm dev` |
|
|
656
|
+
| [custom-node-server](./examples/custom-node-server) | Custom Express server with SSR | 3003 | `pnpm dev` |
|
|
657
|
+
| [cloudflare](./examples/cloudflare) | Cloudflare Workers deployment | 3004 | `pnpm dev` |
|
|
658
|
+
| [client-only](./examples/client-only) | `.client` modules with SSR hydration | 3010 | `pnpm dev` |
|
|
659
|
+
| [epic-stack](./examples/epic-stack) | Full-featured Epic Stack example | 3005 | `pnpm dev` |
|
|
660
|
+
| [federation/epic-stack](./examples/federation/epic-stack) | Module Federation host | 3006 | `pnpm dev` |
|
|
661
|
+
| [federation/epic-stack-remote](./examples/federation/epic-stack-remote) | Module Federation remote | 3007 | `pnpm dev` |
|
|
681
662
|
|
|
682
663
|
Each example has unique ports configured to allow running multiple examples simultaneously.
|
|
683
664
|
|