UNPKG

9.57 kB Markdown View Raw
1---
2title: Framework Adoption from Component Routes
3order: 4
4---
5
6# Framework Adoption from Component Routes
7
8If you are using `<RouterProvider>` please see [Framework Adoption from RouterProvider][upgrade-router-provider] instead.
9
10If you are using `<Routes>` this is the right place.
11
12The React Router Vite plugin adds framework features to React Router. This guide will help you adopt the plugin in your app. If you run into any issues, please reach out for help on [Twitter](https://x.com/remix_run) or [Discord](https://rmx.as/discord).
13
14## Features
15
16The Vite plugin adds:
17
18- Route loaders, actions, and automatic data revalidation
19- Type-safe Routes Modules
20- Automatic route code-splitting
21- Automatic scroll restoration across navigations
22- Optional Static pre-rendering
23- Optional Server rendering
24
25The initial setup requires the most work. However, once complete, you can adopt new features incrementally, one route at a time.
26
27## Prerequisites
28
29To use the Vite plugin, your project requires:
30
31- Node.js 20+ (if using Node as your runtime)
32- Vite 5+
33
34## 1. Install the Vite plugin
35
36**👉 Install the React Router Vite plugin**
37
38```shellscript nonumber
39npm install -D @react-router/dev
40```
41
42**👉 Install a runtime adapter**
43
44We will assume you are using Node as your runtime.
45
46```shellscript nonumber
47npm install @react-router/node
48```
49
50**👉 Swap out the React plugin for React Router.**
51
52```diff filename=vite.config.ts
53-import react from '@vitejs/plugin-react'
54+import { reactRouter } from "@react-router/dev/vite";
55import { defineConfig } from "vite";
56
57
58export default defineConfig({
59 plugins: [
60- react()
61+ reactRouter()
62 ],
63});
64```
65
66## 2. Add the React Router config
67
68**👉 Create a `react-router.config.ts` file**
69
70Add the following to the root of your project. In this config you can tell React Router about your project, like where to find the app directory and to not use SSR (server-side rendering) for now.
71
72```shellscript nonumber
73touch react-router.config.ts
74```
75
76```ts filename=react-router.config.ts
77import type { Config } from "@react-router/dev/config";
78
79export default {
80 appDirectory: "src",
81 ssr: false,
82} satisfies Config;
83```
84
85## 3. Add the Root entry point
86
87In a typical Vite app, the `index.html` file is the entry point for bundling. The React Router Vite plugin moves the entry point to a `root.tsx` file so you can use React to render the shell of your app instead of static HTML, and eventually upgrade to Server Rendering if you want.
88
89**👉 Move your existing `index.html` to `root.tsx`**
90
91For example, if your current `index.html` looks like this:
92
93```html filename=index.html
94<!DOCTYPE html>
95<html lang="en">
96 <head>
97 <meta charset="UTF-8" />
98 <meta
99 name="viewport"
100 content="width=device-width, initial-scale=1.0"
101 />
102 <title>My App</title>
103 </head>
104 <body>
105 <div id="root"></div>
106 <script type="module" src="/src/main.tsx"></script>
107 </body>
108</html>
109```
110
111You would move that markup into `src/root.tsx` and delete `index.html`:
112
113```shellscript nonumber
114touch src/root.tsx
115```
116
117```tsx filename=src/root.tsx
118import {
119 Links,
120 Meta,
121 Outlet,
122 Scripts,
123 ScrollRestoration,
124} from "react-router";
125
126export function Layout({
127 children,
128}: {
129 children: React.ReactNode;
130}) {
131 return (
132 <html lang="en">
133 <head>
134 <meta charSet="UTF-8" />
135 <meta
136 name="viewport"
137 content="width=device-width, initial-scale=1.0"
138 />
139 <title>My App</title>
140 <Meta />
141 <Links />
142 </head>
143 <body>
144 {children}
145 <ScrollRestoration />
146 <Scripts />
147 </body>
148 </html>
149 );
150}
151
152export default function Root() {
153 return <Outlet />;
154}
155```
156
157## 4. Add client entry module
158
159In the typical Vite app the `index.html` file points to `src/main.tsx` as the client entry point. React Router uses a file named `src/entry.client.tsx` instead.
160
161**👉 Make `src/entry.client.tsx` your entry point**
162
163If your current `src/main.tsx` looks like this:
164
165```tsx filename=src/main.tsx
166import React from "react";
167import ReactDOM from "react-dom/client";
168import { BrowserRouter } from "react-router";
169import "./index.css";
170import App from "./App";
171
172ReactDOM.createRoot(
173 document.getElementById("root")!,
174).render(
175 <React.StrictMode>
176 <BrowserRouter>
177 <App />
178 </BrowserRouter>
179 </React.StrictMode>,
180);
181```
182
183You would rename it to `entry.client.tsx` and change it to this:
184
185```tsx filename=src/entry.client.tsx
186import React from "react";
187import ReactDOM from "react-dom/client";
188import { HydratedRouter } from "react-router/dom";
189import "./index.css";
190
191ReactDOM.hydrateRoot(
192 document,
193 <React.StrictMode>
194 <HydratedRouter />
195 </React.StrictMode>,
196);
197```
198
199- Use `hydrateRoot` instead of `createRoot`
200- Render a `<HydratedRouter>` instead of your `<App/>` component
201- Note: we stopped rendering the `<App/>` component. We'll bring it back in a later step, but first we want to get the app to boot with the new entry point.
202
203## 5. Shuffle stuff around
204
205Between `root.tsx` and `entry.client.tsx`, you may want to shuffle some stuff around between them.
206
207In general:
208
209- `root.tsx` contains any rendering things like context providers, layouts, styles, etc.
210- `entry.client.tsx` should be as minimal as possible
211- Remember to _not_ try to render your existing `<App/>` component yet, we'll do that in a later step
212
213Note that your `root.tsx` file will be statically generated and served as the entry point of your app, so just that module will need to be compatible with server rendering. This is where most of your trouble will come.
214
215## 6. Set up your routes
216
217The React Router Vite plugin uses a `routes.ts` file to configure your routes. For now we'll add a simple catchall route to get things going.
218
219**👉 Set up a `catchall.tsx` route**
220
221```shellscript nonumber
222touch src/routes.ts src/catchall.tsx
223```
224
225```ts filename=src/routes.ts
226import {
227 type RouteConfig,
228 route,
229} from "@react-router/dev/routes";
230
231export default [
232 // * matches all URLs, the ? makes it optional so it will match / as well
233 route("*?", "catchall.tsx"),
234] satisfies RouteConfig;
235```
236
237**👉 Render a placeholder route**
238
239Eventually we'll replace this with our original `App` component, but for now we'll just render something simple to make sure we can boot the app.
240
241```tsx filename=src/catchall.tsx
242export default function Component() {
243 return <div>Hello, world!</div>;
244}
245```
246
247[View our guide on configuring routes][configuring-routes] to learn more about the `routes.ts` file.
248
249## 7. Boot the app
250
251At this point you should be able to boot the app and see the root layout.
252
253**👉 Add `dev` script and run the app**
254
255```json filename=package.json
256"scripts": {
257 "dev": "react-router dev"
258}
259```
260
261Now make sure you can boot your app at this point before moving on:
262
263```shellscript
264npm run dev
265```
266
267You will probably want to add `.react-router/` to your `.gitignore` file to avoid tracking unnecessary files in your repository.
268
269```txt
270.react-router/
271```
272
273You can check out [Type Safety][type-safety] to learn how to fully set up and use autogenerated type safety for params, loader data, and more.
274
275## 8. Render your app
276
277To get back to rendering your app, we'll update the "catchall" route we set up earlier that matches all URLs so that your existing `<Routes>` get a chance to render.
278
279**👉 Update the catchall route to render your app**
280
281```tsx filename=src/catchall.tsx
282import App from "./App";
283
284export default function Component() {
285 return <App />;
286}
287```
288
289Your app should be back on the screen and working as usual!
290
291## 9. Migrate a route to a Route Module
292
293You can now incrementally migrate your routes to route modules.
294
295Given an existing route like this:
296
297```tsx filename=src/App.tsx
298// ...
299import About from "./containers/About";
300
301export default function App() {
302 return (
303 <Routes>
304 <Route path="/about" element={<About />} />
305 </Routes>
306 );
307}
308```
309
310**👉 Add the route definition to `routes.ts`**
311
312```tsx filename=src/routes.ts
313import {
314 type RouteConfig,
315 route,
316} from "@react-router/dev/routes";
317
318export default [
319 route("/about", "./pages/about.tsx"),
320 route("*?", "catchall.tsx"),
321] satisfies RouteConfig;
322```
323
324**👉 Add the route module**
325
326Edit the route module to use the [Route Module API][route-modules]:
327
328```tsx filename=src/pages/about.tsx
329export async function clientLoader() {
330 // you can now fetch data here
331 return {
332 title: "About page",
333 };
334}
335
336export default function Component({ loaderData }) {
337 return <h1>{loaderData.title}</h1>;
338}
339```
340
341See [Type Safety][type-safety] to set up autogenerated type safety for params, loader data, and more.
342
343The first few routes you migrate are the hardest because you often have to access various abstractions a bit differently than before (like in a loader instead of from a hook or context). But once the trickiest bits get dealt with, you get into an incremental groove.
344
345## Enable SSR and/or Pre-rendering
346
347If you want to enable server rendering and static pre-rendering, you can do so with the `ssr` and `prerender` options in the bundler plugin. For SSR you'll need to also deploy the server build to a server.
348
349```ts filename=react-router.config.ts
350import type { Config } from "@react-router/dev/config";
351
352export default {
353 ssr: true,
354 async prerender() {
355 return ["/", "/about", "/contact"];
356 },
357} satisfies Config;
358```
359
360[upgrade-router-provider]: ./router-provider
361[configuring-routes]: ../start/framework/routing
362[route-modules]: ../start/framework/route-module
363[type-safety]: ../how-to/route-module-type-safety
364
\No newline at end of file