rsbuild-plugin-react-router 0.0.4 → 0.1.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 +214 -3
- package/dist/906.js +1 -0
- package/dist/946.js +1 -0
- package/dist/babel.d.ts +2 -2
- package/dist/build-manifest.d.ts +19 -0
- package/dist/constants.d.ts +10 -3
- package/dist/export-utils.d.ts +7 -0
- package/dist/index.cjs +1825 -639
- package/dist/index.js +1594 -476
- package/dist/manifest.d.ts +18 -1
- package/dist/modify-browser-manifest.d.ts +7 -1
- package/dist/plugin-utils.d.ts +2 -0
- package/dist/prerender.d.ts +16 -0
- package/dist/react-router-config.d.ts +51 -0
- package/dist/route-chunks.d.ts +32 -0
- package/dist/route-config.d.ts +13 -0
- package/dist/rslib-runtime.js +23 -0
- package/dist/server-utils.d.ts +27 -5
- package/dist/ssr-externals.d.ts +1 -0
- package/dist/templates/entry.client.cjs +5 -7
- package/dist/templates/entry.client.js +5 -5
- package/dist/templates/entry.server.cjs +7 -6
- package/dist/templates/entry.server.js +10 -11
- package/dist/types.d.ts +6 -0
- package/dist/validation/validate-plugin-order.d.ts +9 -0
- package/dist/warnings/warn-on-client-source-maps.d.ts +6 -0
- package/package.json +45 -47
- package/dist/transform-route-federation.d.ts +0 -6
package/README.md
CHANGED
|
@@ -8,13 +8,17 @@ A Rsbuild plugin that provides seamless integration with React Router, supportin
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
- 🚀 Zero-config setup with sensible defaults
|
|
12
13
|
- 🔄 Automatic route generation from file system
|
|
13
14
|
- 🖥️ Server-Side Rendering (SSR) support
|
|
14
|
-
- 📱 Client-side navigation
|
|
15
|
+
- 📱 Client-side navigation with SPA mode (`ssr: false`)
|
|
16
|
+
- 📄 Static prerendering for hybrid static/dynamic sites
|
|
15
17
|
- 🛠️ TypeScript support out of the box
|
|
16
18
|
- 🔧 Customizable configuration
|
|
17
19
|
- 🎯 Support for route-level code splitting
|
|
20
|
+
- ☁️ Cloudflare Workers deployment support
|
|
21
|
+
- 🔗 Module Federation support (experimental)
|
|
18
22
|
|
|
19
23
|
## Installation
|
|
20
24
|
|
|
@@ -26,6 +30,18 @@ yarn add rsbuild-plugin-react-router
|
|
|
26
30
|
pnpm add rsbuild-plugin-react-router
|
|
27
31
|
```
|
|
28
32
|
|
|
33
|
+
## Local development
|
|
34
|
+
|
|
35
|
+
For the federation examples and Playwright e2e tests, use Node 22 and the
|
|
36
|
+
repo-pinned pnpm version:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
nvm install
|
|
40
|
+
nvm use
|
|
41
|
+
corepack enable
|
|
42
|
+
corepack prepare pnpm@9.15.3 --activate
|
|
43
|
+
```
|
|
44
|
+
|
|
29
45
|
## Usage
|
|
30
46
|
|
|
31
47
|
Add the plugin to your `rsbuild.config.ts`:
|
|
@@ -43,7 +59,7 @@ export default defineConfig(() => {
|
|
|
43
59
|
customServer: false,
|
|
44
60
|
// Optional: Specify server output format
|
|
45
61
|
serverOutput: "commonjs",
|
|
46
|
-
//Optional: enable experimental support for module federation
|
|
62
|
+
// Optional: enable experimental support for module federation
|
|
47
63
|
federation: false
|
|
48
64
|
}),
|
|
49
65
|
pluginReact()
|
|
@@ -78,9 +94,18 @@ pluginReactRouter({
|
|
|
78
94
|
*/
|
|
79
95
|
federation?: boolean
|
|
80
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.
|
|
81
106
|
```
|
|
82
107
|
|
|
83
|
-
2. **React Router Configuration** (in `react-router.config
|
|
108
|
+
2. **React Router Configuration** (in `react-router.config.*`):
|
|
84
109
|
```ts
|
|
85
110
|
import type { Config } from '@react-router/dev/config';
|
|
86
111
|
|
|
@@ -91,6 +116,31 @@ export default {
|
|
|
91
116
|
*/
|
|
92
117
|
ssr: true,
|
|
93
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
|
+
|
|
94
144
|
/**
|
|
95
145
|
* Build directory for output files
|
|
96
146
|
* @default 'build'
|
|
@@ -108,11 +158,110 @@ export default {
|
|
|
108
158
|
* @default '/'
|
|
109
159
|
*/
|
|
110
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
|
+
},
|
|
111
169
|
} satisfies Config;
|
|
112
170
|
```
|
|
113
171
|
|
|
114
172
|
All configuration options are optional and will use sensible defaults if not specified.
|
|
115
173
|
|
|
174
|
+
### Config File Resolution
|
|
175
|
+
|
|
176
|
+
The plugin will look for `react-router.config` with any supported JS/TS extension, in this order:
|
|
177
|
+
|
|
178
|
+
- `react-router.config.tsx`
|
|
179
|
+
- `react-router.config.ts`
|
|
180
|
+
- `react-router.config.mts`
|
|
181
|
+
- `react-router.config.jsx`
|
|
182
|
+
- `react-router.config.js`
|
|
183
|
+
- `react-router.config.mjs`
|
|
184
|
+
|
|
185
|
+
If none are found, it falls back to defaults.
|
|
186
|
+
|
|
187
|
+
### Framework Mode
|
|
188
|
+
|
|
189
|
+
React Router Framework Mode is implemented as a Vite plugin. This Rsbuild
|
|
190
|
+
plugin targets Data Mode only and does not support Framework Mode.
|
|
191
|
+
|
|
192
|
+
### FAQ
|
|
193
|
+
|
|
194
|
+
#### rsbuild-plugin-react-router vs ModernJS
|
|
195
|
+
|
|
196
|
+
This plugin is a lightweight adapter to run React Router on Rsbuild. It does
|
|
197
|
+
not aim to replace ModernJS or its higher-level framework features. If your
|
|
198
|
+
goal is a full framework or advanced microfrontend support, ModernJS may be
|
|
199
|
+
a better fit.
|
|
200
|
+
|
|
201
|
+
### SPA Mode (`ssr: false`)
|
|
202
|
+
|
|
203
|
+
React Router's SPA Mode still requires a build-time server render of the root route to generate a hydratable `index.html` (this is how the official React Router Vite plugin works).
|
|
204
|
+
|
|
205
|
+
When `ssr: false`:
|
|
206
|
+
|
|
207
|
+
- The plugin builds both `web` and `node` internally.
|
|
208
|
+
- It generates `build/client/index.html` by running the server build once (requesting `basename` with the `X-React-Router-SPA-Mode: yes` header).
|
|
209
|
+
- It removes `build/server` after generating `index.html`, so the output is deployable as static assets.
|
|
210
|
+
|
|
211
|
+
**Important:** In SPA mode, use `clientLoader` instead of `loader` for data loading since there's no server at runtime.
|
|
212
|
+
|
|
213
|
+
### Static Prerendering
|
|
214
|
+
|
|
215
|
+
For static sites with multiple pages, you can prerender specific routes at build time:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
// react-router.config.ts
|
|
219
|
+
import type { Config } from '@react-router/dev/config';
|
|
220
|
+
|
|
221
|
+
export default {
|
|
222
|
+
ssr: false,
|
|
223
|
+
prerender: [
|
|
224
|
+
'/',
|
|
225
|
+
'/about',
|
|
226
|
+
'/docs',
|
|
227
|
+
'/docs/getting-started',
|
|
228
|
+
'/docs/advanced',
|
|
229
|
+
'/projects',
|
|
230
|
+
],
|
|
231
|
+
} satisfies Config;
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
When `prerender` is specified:
|
|
235
|
+
|
|
236
|
+
- Each path in the array is rendered at build time
|
|
237
|
+
- Static HTML files are generated for each route (e.g., `/about` → `build/client/about/index.html`)
|
|
238
|
+
- The server build is removed after prerendering for static deployment
|
|
239
|
+
- Non-prerendered routes fall back to client-side routing
|
|
240
|
+
|
|
241
|
+
You can also use `prerender: true` to prerender all static routes automatically.
|
|
242
|
+
|
|
243
|
+
`prerender` can also be a function:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
export default {
|
|
247
|
+
ssr: false,
|
|
248
|
+
prerender: ({ getStaticPaths }) =>
|
|
249
|
+
getStaticPaths().filter(path => path !== '/admin'),
|
|
250
|
+
} satisfies Config;
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
For large sites, you can tune prerender concurrency:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
export default {
|
|
257
|
+
ssr: false,
|
|
258
|
+
prerender: {
|
|
259
|
+
paths: ['/','/about'],
|
|
260
|
+
unstable_concurrency: 4,
|
|
261
|
+
},
|
|
262
|
+
} satisfies Config;
|
|
263
|
+
```
|
|
264
|
+
|
|
116
265
|
### Default Configuration Values
|
|
117
266
|
|
|
118
267
|
If no configuration is provided, the following defaults will be used:
|
|
@@ -187,6 +336,7 @@ Route components support the following exports:
|
|
|
187
336
|
- `Layout` - Layout component
|
|
188
337
|
- `clientLoader` - Client-side data loading
|
|
189
338
|
- `clientAction` - Client-side form actions
|
|
339
|
+
- `clientMiddleware` - Client-side middleware
|
|
190
340
|
- `handle` - Route handle
|
|
191
341
|
- `links` - Prefetch links
|
|
192
342
|
- `meta` - Route meta data
|
|
@@ -195,8 +345,24 @@ Route components support the following exports:
|
|
|
195
345
|
#### Server-side Exports
|
|
196
346
|
- `loader` - Server-side data loading
|
|
197
347
|
- `action` - Server-side form actions
|
|
348
|
+
- `middleware` - Server-side middleware
|
|
198
349
|
- `headers` - HTTP headers
|
|
199
350
|
|
|
351
|
+
### Client/Server-only Modules
|
|
352
|
+
|
|
353
|
+
- Files ending in `.client.*` are treated as client-only. Their exports are
|
|
354
|
+
stubbed to `undefined` in the server build, so they are safe to import from
|
|
355
|
+
route components for browser-only behavior.
|
|
356
|
+
- Files ending in `.server.*` are server-only. If they are imported by code
|
|
357
|
+
compiled for the web environment, the build will fail with a clear error.
|
|
358
|
+
Keep `.server` imports in server entrypoints or other server-only code.
|
|
359
|
+
|
|
360
|
+
### Asset Prefix
|
|
361
|
+
|
|
362
|
+
If you configure `output.assetPrefix` in Rsbuild, the plugin uses that value
|
|
363
|
+
for the React Router browser manifest and server build `publicPath` so asset
|
|
364
|
+
URLs resolve correctly when serving from a CDN or sub-path.
|
|
365
|
+
|
|
200
366
|
## Custom Server Setup
|
|
201
367
|
|
|
202
368
|
The plugin supports two ways to handle server-side rendering:
|
|
@@ -479,6 +645,51 @@ The plugin automatically:
|
|
|
479
645
|
- Handles route-based code splitting
|
|
480
646
|
- Manages client and server builds
|
|
481
647
|
|
|
648
|
+
## React Router Framework Mode
|
|
649
|
+
|
|
650
|
+
React Router "Framework Mode" wraps Data Mode using a Vite plugin. This Rsbuild plugin currently targets React Router's Data Mode build/runtime model and does not implement the Vite plugin layer (type-safe href, route module splitting, etc.).
|
|
651
|
+
|
|
652
|
+
## Examples
|
|
653
|
+
|
|
654
|
+
The repository includes several examples demonstrating different use cases:
|
|
655
|
+
|
|
656
|
+
| Example | Description | Port | Command |
|
|
657
|
+
|---------|-------------|------|---------|
|
|
658
|
+
| [default-template](./examples/default-template) | Standard SSR setup with React Router | 3000 | `pnpm dev` |
|
|
659
|
+
| [spa-mode](./examples/spa-mode) | Single Page Application (`ssr: false`) | 3001 | `pnpm dev` |
|
|
660
|
+
| [prerender](./examples/prerender) | Static prerendering for multiple routes | 3002 | `pnpm dev` |
|
|
661
|
+
| [custom-node-server](./examples/custom-node-server) | Custom Express server with SSR | 3003 | `pnpm dev` |
|
|
662
|
+
| [cloudflare](./examples/cloudflare) | Cloudflare Workers deployment | 3004 | `pnpm dev` |
|
|
663
|
+
| [client-only](./examples/client-only) | `.client` modules with SSR hydration | 3010 | `pnpm dev` |
|
|
664
|
+
| [epic-stack](./examples/epic-stack) | Full-featured Epic Stack example | 3005 | `pnpm dev` |
|
|
665
|
+
| [federation/epic-stack](./examples/federation/epic-stack) | Module Federation host | 3006 | `pnpm dev` |
|
|
666
|
+
| [federation/epic-stack-remote](./examples/federation/epic-stack-remote) | Module Federation remote | 3007 | `pnpm dev` |
|
|
667
|
+
|
|
668
|
+
Each example has unique ports configured to allow running multiple examples simultaneously.
|
|
669
|
+
|
|
670
|
+
### Running Examples
|
|
671
|
+
|
|
672
|
+
```bash
|
|
673
|
+
# Install dependencies
|
|
674
|
+
pnpm install
|
|
675
|
+
|
|
676
|
+
# Build the plugin
|
|
677
|
+
pnpm build
|
|
678
|
+
|
|
679
|
+
# Run any example
|
|
680
|
+
cd examples/default-template
|
|
681
|
+
pnpm dev
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Running E2E Tests
|
|
685
|
+
|
|
686
|
+
Each example includes Playwright e2e tests:
|
|
687
|
+
|
|
688
|
+
```bash
|
|
689
|
+
cd examples/default-template
|
|
690
|
+
pnpm test:e2e
|
|
691
|
+
```
|
|
692
|
+
|
|
482
693
|
## License
|
|
483
694
|
|
|
484
695
|
MIT
|
package/dist/906.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ServerRouter, createRequestHandler, matchRoutes } from "react-router";
|
package/dist/946.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { StrictMode, createElement, startTransition } from "react";
|
package/dist/babel.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { types as Babel } from '@babel/core';
|
|
|
2
2
|
import { type ParseResult, parse } from '@babel/parser';
|
|
3
3
|
import type { NodePath } from '@babel/traverse';
|
|
4
4
|
import * as t from '@babel/types';
|
|
5
|
-
declare const traverse: typeof import(
|
|
6
|
-
declare const generate: typeof import(
|
|
5
|
+
declare const traverse: typeof import('@babel/traverse').default;
|
|
6
|
+
declare const generate: typeof import('@babel/generator').default;
|
|
7
7
|
export { traverse, generate, parse, t };
|
|
8
8
|
export type { Babel, NodePath, ParseResult };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Config } from './react-router-config.js';
|
|
2
|
+
import type { Route } from './types.js';
|
|
3
|
+
type BuildManifest = {
|
|
4
|
+
routes: Record<string, Route>;
|
|
5
|
+
} | {
|
|
6
|
+
routes: Record<string, Route>;
|
|
7
|
+
serverBundles: Record<string, {
|
|
8
|
+
id: string;
|
|
9
|
+
file: string;
|
|
10
|
+
}>;
|
|
11
|
+
routeIdToServerBundleId: Record<string, string>;
|
|
12
|
+
};
|
|
13
|
+
export declare const getBuildManifest: ({ reactRouterConfig, routes, rootDirectory, }: {
|
|
14
|
+
reactRouterConfig: Required<Pick<Config, "appDirectory" | "buildDirectory" | "serverBuildFile" | "future">> & Pick<Config, "serverBundles">;
|
|
15
|
+
routes: Record<string, Route>;
|
|
16
|
+
rootDirectory: string;
|
|
17
|
+
}) => Promise<BuildManifest | undefined>;
|
|
18
|
+
export declare const getRoutesByServerBundleId: (buildManifest: BuildManifest | undefined) => Record<string, Record<string, Route>>;
|
|
19
|
+
export {};
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
export declare const PLUGIN_NAME = "rsbuild:react-router";
|
|
2
|
-
export declare const JS_EXTENSIONS: readonly [".tsx", ".ts", ".jsx", ".js", ".mjs"];
|
|
2
|
+
export declare const JS_EXTENSIONS: readonly [".tsx", ".ts", ".jsx", ".js", ".mjs", ".mts"];
|
|
3
3
|
export declare const JS_LOADERS: {
|
|
4
4
|
readonly '.ts': "ts";
|
|
5
5
|
readonly '.tsx': "tsx";
|
|
6
6
|
readonly '.js': "js";
|
|
7
7
|
readonly '.jsx': "jsx";
|
|
8
|
+
readonly '.mjs': "js";
|
|
9
|
+
readonly '.mts': "ts";
|
|
8
10
|
};
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const
|
|
11
|
+
export declare const BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
|
|
12
|
+
export declare const SERVER_ONLY_ROUTE_EXPORTS: readonly ["loader", "action", "middleware", "headers"];
|
|
13
|
+
export declare const CLIENT_NON_COMPONENT_EXPORTS: readonly ["clientAction", "clientLoader", "clientMiddleware", "handle", "meta", "links", "shouldRevalidate"];
|
|
14
|
+
export declare const CLIENT_COMPONENT_EXPORTS: readonly ["default", "ErrorBoundary", "HydrateFallback", "Layout"];
|
|
15
|
+
export declare const CLIENT_ROUTE_EXPORTS: readonly ((typeof CLIENT_NON_COMPONENT_EXPORTS)[number] | (typeof CLIENT_COMPONENT_EXPORTS)[number])[];
|
|
11
16
|
export declare const NAMED_COMPONENT_EXPORTS: readonly ["HydrateFallback", "ErrorBoundary"];
|
|
12
17
|
export declare const SERVER_EXPORTS: {
|
|
13
18
|
readonly loader: "loader";
|
|
14
19
|
readonly action: "action";
|
|
20
|
+
readonly middleware: "middleware";
|
|
15
21
|
readonly headers: "headers";
|
|
16
22
|
};
|
|
17
23
|
export declare const CLIENT_EXPORTS: {
|
|
18
24
|
readonly clientAction: "clientAction";
|
|
19
25
|
readonly clientLoader: "clientLoader";
|
|
26
|
+
readonly clientMiddleware: "clientMiddleware";
|
|
20
27
|
readonly default: "default";
|
|
21
28
|
readonly ErrorBoundary: "ErrorBoundary";
|
|
22
29
|
readonly handle: "handle";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const transformToEsm: (code: string, resourcePath: string) => Promise<string>;
|
|
2
|
+
export declare const getExportNames: (code: string) => Promise<string[]>;
|
|
3
|
+
export declare const getExportNamesAndExportAll: (code: string) => Promise<{
|
|
4
|
+
exportNames: string[];
|
|
5
|
+
exportAllModules: string[];
|
|
6
|
+
}>;
|
|
7
|
+
export declare const getRouteModuleExports: (resourcePath: string) => Promise<string[]>;
|