Skip to content

Commit 753d096

Browse files
ScriptedAlchemychenjiahan
authored andcommitted
feat: enhance documentation and configuration for React Router plugin
- Completely rewrote README.md with comprehensive documentation - Updated example project configuration and routes - Improved dev server and plugin configuration handling - Added more detailed styling and interactive elements to documentation pages - Refined plugin options and configuration management - Enhanced server-side rendering and custom server support
1 parent 0044ff1 commit 753d096

File tree

13 files changed

+868
-293
lines changed

13 files changed

+868
-293
lines changed

README.md

Lines changed: 308 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,320 @@
1+
# @rsbuild/plugin-react-router
2+
13
<p align="center">
24
<a href="https://rsbuild.dev" target="blank"><img src="https://github.com/web-infra-dev/rsbuild/assets/7237365/84abc13e-b620-468f-a90b-dbf28e7e9427" alt="Rsbuild Logo" /></a>
35
</p>
46

5-
# Rsbuild
7+
A Rsbuild plugin that provides seamless integration with React Router, supporting both client-side routing and server-side rendering (SSR).
8+
9+
## Features
10+
11+
- 🚀 Zero-config setup with sensible defaults
12+
- 🔄 Automatic route generation from file system
13+
- 🖥️ Server-Side Rendering (SSR) support
14+
- 📱 Client-side navigation
15+
- 🛠️ TypeScript support out of the box
16+
- 🔧 Customizable configuration
17+
- 🎯 Support for route-level code splitting
18+
19+
## Installation
20+
21+
```bash
22+
npm install @rsbuild/plugin-react-router
23+
# or
24+
yarn add @rsbuild/plugin-react-router
25+
# or
26+
pnpm add @rsbuild/plugin-react-router
27+
```
28+
29+
## Usage
30+
31+
Add the plugin to your `rsbuild.config.ts`:
32+
33+
```ts
34+
import { defineConfig } from '@rsbuild/core';
35+
import { pluginReactRouter } from '@rsbuild/plugin-react-router';
36+
import { pluginReact } from '@rsbuild/plugin-react';
37+
38+
export default defineConfig(() => {
39+
return {
40+
plugins: [
41+
pluginReactRouter({
42+
// Optional: Enable custom server mode
43+
customServer: false,
44+
}),
45+
pluginReact()
46+
],
47+
};
48+
});
49+
```
50+
51+
## Configuration
52+
53+
The plugin uses a two-part configuration system:
54+
55+
1. **Plugin Options** (in `rsbuild.config.ts`):
56+
```ts
57+
pluginReactRouter({
58+
/**
59+
* Whether to disable automatic middleware setup for custom server implementation.
60+
* Enable this when you want to handle server setup manually.
61+
* @default false
62+
*/
63+
customServer?: boolean
64+
})
65+
```
66+
67+
2. **React Router Configuration** (in `react-router.config.ts`):
68+
```ts
69+
import type { Config } from '@react-router/dev/config';
70+
71+
export default {
72+
/**
73+
* Whether to enable Server-Side Rendering (SSR) support.
74+
* @default true
75+
*/
76+
ssr: true,
77+
78+
/**
79+
* Build directory for output files
80+
* @default 'build'
81+
*/
82+
buildDirectory: 'dist',
83+
84+
/**
85+
* Application source directory
86+
* @default 'app'
87+
*/
88+
appDirectory: 'src/app',
89+
90+
/**
91+
* Base URL path
92+
* @default '/'
93+
*/
94+
basename: '/my-app',
95+
} satisfies Config;
96+
```
97+
98+
All configuration options are optional and will use sensible defaults if not specified.
99+
100+
### Default Configuration Values
101+
102+
If no configuration is provided, the following defaults will be used:
103+
104+
```ts
105+
// Plugin defaults (rsbuild.config.ts)
106+
{
107+
customServer: false
108+
}
109+
110+
// Router defaults (react-router.config.ts)
111+
{
112+
ssr: true,
113+
buildDirectory: 'build',
114+
appDirectory: 'app',
115+
basename: '/'
116+
}
117+
```
118+
119+
### Route Configuration
120+
121+
Routes can be defined in `app/routes.ts` using the helper functions from `@react-router/dev/routes`:
122+
123+
```ts
124+
import {
125+
type RouteConfig,
126+
index,
127+
layout,
128+
prefix,
129+
route,
130+
} from '@react-router/dev/routes';
131+
132+
export default [
133+
// Index route for the home page
134+
index('routes/home.tsx'),
135+
136+
// Regular route
137+
route('about', 'routes/about.tsx'),
138+
139+
// Nested routes with a layout
140+
layout('routes/docs/layout.tsx', [
141+
index('routes/docs/index.tsx'),
142+
route('getting-started', 'routes/docs/getting-started.tsx'),
143+
route('advanced', 'routes/docs/advanced.tsx'),
144+
]),
145+
146+
// Routes with dynamic segments
147+
...prefix('projects', [
148+
index('routes/projects/index.tsx'),
149+
layout('routes/projects/layout.tsx', [
150+
route(':projectId', 'routes/projects/project.tsx'),
151+
route(':projectId/edit', 'routes/projects/edit.tsx'),
152+
]),
153+
]),
154+
] satisfies RouteConfig;
155+
```
156+
157+
The plugin provides several helper functions for defining routes:
158+
- `index()` - Creates an index route
159+
- `route()` - Creates a regular route with a path
160+
- `layout()` - Creates a layout route with nested children
161+
- `prefix()` - Adds a URL prefix to a group of routes
162+
163+
### Route Components
164+
165+
Route components support the following exports:
166+
167+
#### Client-side Exports
168+
- `default` - The route component
169+
- `ErrorBoundary` - Error boundary component
170+
- `HydrateFallback` - Loading component during hydration
171+
- `Layout` - Layout component
172+
- `clientLoader` - Client-side data loading
173+
- `clientAction` - Client-side form actions
174+
- `handle` - Route handle
175+
- `links` - Prefetch links
176+
- `meta` - Route meta data
177+
- `shouldRevalidate` - Revalidation control
178+
179+
#### Server-side Exports
180+
- `loader` - Server-side data loading
181+
- `action` - Server-side form actions
182+
- `headers` - HTTP headers
183+
184+
## Custom Server Setup
185+
186+
The plugin supports two ways to handle server-side rendering:
187+
188+
1. **Default Server Setup**: By default, the plugin automatically sets up the necessary middleware for SSR.
189+
190+
2. **Custom Server Setup**: For more control, you can disable the automatic middleware setup by enabling custom server mode:
191+
192+
```ts
193+
// rsbuild.config.ts
194+
import { defineConfig } from '@rsbuild/core';
195+
import { pluginReactRouter } from '@rsbuild/plugin-react-router';
196+
import { pluginReact } from '@rsbuild/plugin-react';
197+
198+
export default defineConfig(() => {
199+
return {
200+
plugins: [
201+
pluginReactRouter({
202+
customServer: true
203+
}),
204+
pluginReact()
205+
],
206+
};
207+
});
208+
```
209+
210+
When using a custom server, you'll need to:
211+
212+
1. Create a server handler (`server/app.ts`):
213+
```ts
214+
import { createRequestHandler } from '@react-router/express';
215+
216+
export const app = createRequestHandler({
217+
build: () => import('virtual/react-router/server-build'),
218+
getLoadContext() {
219+
// Add custom context available to your loaders/actions
220+
return {
221+
// ... your custom context
222+
};
223+
},
224+
});
225+
```
226+
227+
2. Set up your server entry point (`server.js`):
228+
```js
229+
import { createRsbuild, loadConfig } from '@rsbuild/core';
230+
import express from 'express';
231+
import path from 'path';
232+
import { fileURLToPath } from 'url';
233+
234+
const __filename = fileURLToPath(import.meta.url);
235+
const __dirname = path.dirname(__filename);
236+
237+
const app = express();
238+
const isDev = process.env.NODE_ENV !== 'production';
239+
240+
async function startServer() {
241+
if (isDev) {
242+
const config = await loadConfig();
243+
const rsbuild = await createRsbuild({
244+
rsbuildConfig: config.content,
245+
});
246+
const devServer = await rsbuild.createDevServer();
247+
app.use(devServer.middlewares);
248+
249+
app.use(async (req, res, next) => {
250+
try {
251+
const bundle = await devServer.environments.node.loadBundle('app');
252+
await bundle.app(req, res, next);
253+
} catch (e) {
254+
next(e);
255+
}
256+
});
257+
258+
const port = Number.parseInt(process.env.PORT || '3000', 10);
259+
const server = app.listen(port, () => {
260+
console.log(`Development server is running on http://localhost:${port}`);
261+
devServer.afterListen();
262+
});
263+
devServer.connectWebSocket({ server });
264+
} else {
265+
// Production mode
266+
app.use(express.static(path.join(__dirname, 'build/client'), {
267+
index: false
268+
}));
269+
270+
// Load the server bundle
271+
const serverBundle = await import('./build/server/static/js/app.js');
272+
// Mount the server app after static file handling
273+
app.use(async (req, res, next) => {
274+
try {
275+
await serverBundle.default.app(req, res, next);
276+
} catch (e) {
277+
next(e);
278+
}
279+
});
280+
281+
const port = Number.parseInt(process.env.PORT || '3000', 10);
282+
app.listen(port, () => {
283+
console.log(`Production server is running on http://localhost:${port}`);
284+
});
285+
}
286+
}
6287

7-
The Rspack-based build tool. It's fast, out-of-the-box and extensible.
288+
startServer().catch(console.error);
289+
```
8290
9-
## Documentation
291+
3. Update your `package.json` scripts:
292+
```json
293+
{
294+
"scripts": {
295+
"dev": "node server.js",
296+
"build": "rsbuild build",
297+
"start": "NODE_ENV=production node server.js"
298+
}
299+
}
300+
```
10301
11-
https://rsbuild.dev/
302+
The custom server setup allows you to:
303+
- Add custom middleware
304+
- Handle API routes
305+
- Integrate with databases
306+
- Implement custom authentication
307+
- Add server-side caching
308+
- And more!
12309
13-
## Contributing
310+
## Development
14311
15-
Please read the [Contributing Guide](https://github.com/web-infra-dev/rsbuild/blob/main/CONTRIBUTING.md).
312+
The plugin automatically:
313+
- Runs type generation during development and build
314+
- Sets up development server with live reload
315+
- Handles route-based code splitting
316+
- Manages client and server builds
16317
17318
## License
18319
19-
Rsbuild is [MIT licensed](https://github.com/web-infra-dev/rsbuild/blob/main/LICENSE).
320+
MIT

examples/custom-node-server/app/routes.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ export default [
1414
route('about', 'routes/about.tsx'),
1515

1616
// Docs section with nested routes
17-
layout('routes/docs/layout.tsx', [
18-
index('routes/docs/index.tsx'),
19-
route('getting-started', 'routes/docs/getting-started.tsx'),
20-
route('advanced', 'routes/docs/advanced.tsx'),
17+
...prefix('docs', [
18+
layout('routes/docs/layout.tsx', [
19+
index('routes/docs/index.tsx'),
20+
route('getting-started', 'routes/docs/getting-started.tsx'),
21+
route('advanced', 'routes/docs/advanced.tsx'),
22+
]),
2123
]),
2224

2325
// Projects section with dynamic segments

0 commit comments

Comments
 (0)