react-router 7.16.0 → 7.17.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.
Files changed (137) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/development/{browser-nIQ4Nsyi.d.mts → browser-CGcs-0pD.d.mts} +1 -1
  3. package/dist/development/{chunk-QUQL4437.mjs → chunk-6CSD65Y2.mjs} +2 -2
  4. package/dist/{production/chunk-NALGHHKE.mjs → development/chunk-ASILSGTR.mjs} +2 -2
  5. package/dist/development/{chunk-SRID2YZ2.js → chunk-KFNXW4AL.js} +1 -1
  6. package/dist/development/{chunk-XEJDWL2B.js → chunk-PBLBZ3QU.js} +7 -7
  7. package/dist/{production/chunk-SKEDDLRM.js → development/chunk-PULC7NLK.js} +99 -99
  8. package/dist/development/{context-m8rizgnE.d.mts → context-CmHpk1Ws.d.mts} +1 -1
  9. package/dist/development/dom-export.d.mts +3 -3
  10. package/dist/development/dom-export.d.ts +1 -1
  11. package/dist/development/dom-export.js +28 -28
  12. package/dist/development/dom-export.mjs +3 -3
  13. package/dist/development/{index-react-server-client-BLiUx67a.d.ts → index-react-server-client-CwU9bE5R.d.ts} +1 -1
  14. package/dist/development/{index-react-server-client-CdKROblb.d.mts → index-react-server-client-DPrDrCew.d.mts} +1 -1
  15. package/dist/development/index-react-server-client.d.mts +2 -2
  16. package/dist/development/index-react-server-client.d.ts +1 -1
  17. package/dist/development/index-react-server-client.js +4 -4
  18. package/dist/development/index-react-server-client.mjs +2 -2
  19. package/dist/development/index-react-server.js +1 -1
  20. package/dist/development/index-react-server.mjs +1 -1
  21. package/dist/development/index.d.mts +6 -6
  22. package/dist/development/index.d.ts +2 -2
  23. package/dist/development/index.js +85 -85
  24. package/dist/development/index.mjs +3 -3
  25. package/dist/development/lib/types/internal.js +1 -1
  26. package/dist/development/lib/types/internal.mjs +1 -1
  27. package/dist/production/{browser-nIQ4Nsyi.d.mts → browser-CGcs-0pD.d.mts} +1 -1
  28. package/dist/{development/chunk-S54KXAEJ.mjs → production/chunk-5TQZEVD5.mjs} +2 -2
  29. package/dist/production/{chunk-EAQNHM3N.js → chunk-CTIXC7EV.js} +7 -7
  30. package/dist/{development/chunk-IBI7OMNB.js → production/chunk-EN242BO4.js} +99 -99
  31. package/dist/production/{chunk-Q65P7S7Y.mjs → chunk-OSYEOCBT.mjs} +2 -2
  32. package/dist/production/{chunk-Y7DNFQZP.js → chunk-RTRY3JFT.js} +1 -1
  33. package/dist/production/{context-m8rizgnE.d.mts → context-CmHpk1Ws.d.mts} +1 -1
  34. package/dist/production/dom-export.d.mts +3 -3
  35. package/dist/production/dom-export.d.ts +1 -1
  36. package/dist/production/dom-export.js +28 -28
  37. package/dist/production/dom-export.mjs +3 -3
  38. package/dist/production/{index-react-server-client-BLiUx67a.d.ts → index-react-server-client-CwU9bE5R.d.ts} +1 -1
  39. package/dist/production/{index-react-server-client-CdKROblb.d.mts → index-react-server-client-DPrDrCew.d.mts} +1 -1
  40. package/dist/production/index-react-server-client.d.mts +2 -2
  41. package/dist/production/index-react-server-client.d.ts +1 -1
  42. package/dist/production/index-react-server-client.js +4 -4
  43. package/dist/production/index-react-server-client.mjs +2 -2
  44. package/dist/production/index-react-server.js +1 -1
  45. package/dist/production/index-react-server.mjs +1 -1
  46. package/dist/production/index.d.mts +6 -6
  47. package/dist/production/index.d.ts +2 -2
  48. package/dist/production/index.js +85 -85
  49. package/dist/production/index.mjs +3 -3
  50. package/dist/production/lib/types/internal.js +1 -1
  51. package/dist/production/lib/types/internal.mjs +1 -1
  52. package/docs/explanation/backend-for-frontend.md +50 -0
  53. package/docs/explanation/code-splitting.md +61 -0
  54. package/docs/explanation/concurrency.md +135 -0
  55. package/docs/explanation/form-vs-fetcher.md +292 -0
  56. package/docs/explanation/hot-module-replacement.md +137 -0
  57. package/docs/explanation/hydration.md +14 -0
  58. package/docs/explanation/index-query-param.md +86 -0
  59. package/docs/explanation/index.md +4 -0
  60. package/docs/explanation/lazy-route-discovery.md +78 -0
  61. package/docs/explanation/location.md +6 -0
  62. package/docs/explanation/progressive-enhancement.md +150 -0
  63. package/docs/explanation/race-conditions.md +88 -0
  64. package/docs/explanation/react-transitions.md +160 -0
  65. package/docs/explanation/route-matching.md +7 -0
  66. package/docs/explanation/server-client-execution.md +4 -0
  67. package/docs/explanation/sessions-and-cookies.md +465 -0
  68. package/docs/explanation/special-files.md +16 -0
  69. package/docs/explanation/state-management.md +524 -0
  70. package/docs/explanation/styling.md +87 -0
  71. package/docs/explanation/type-safety.md +82 -0
  72. package/docs/how-to/accessibility.md +44 -0
  73. package/docs/how-to/client-data.md +199 -0
  74. package/docs/how-to/data-strategy.md +317 -0
  75. package/docs/how-to/error-boundary.md +231 -0
  76. package/docs/how-to/error-reporting.md +142 -0
  77. package/docs/how-to/fetchers.md +307 -0
  78. package/docs/how-to/file-route-conventions.md +410 -0
  79. package/docs/how-to/file-uploads.md +217 -0
  80. package/docs/how-to/form-validation.md +120 -0
  81. package/docs/how-to/headers.md +164 -0
  82. package/docs/how-to/index.md +4 -0
  83. package/docs/how-to/instrumentation.md +556 -0
  84. package/docs/how-to/meta.md +40 -0
  85. package/docs/how-to/middleware.md +763 -0
  86. package/docs/how-to/navigation-blocking.md +233 -0
  87. package/docs/how-to/optimize-revalidation.md +12 -0
  88. package/docs/how-to/pre-rendering.md +225 -0
  89. package/docs/how-to/presets.md +103 -0
  90. package/docs/how-to/react-server-components.md +899 -0
  91. package/docs/how-to/resource-routes.md +126 -0
  92. package/docs/how-to/route-module-type-safety.md +100 -0
  93. package/docs/how-to/search-params.md +4 -0
  94. package/docs/how-to/security.md +30 -0
  95. package/docs/how-to/server-bundles.md +66 -0
  96. package/docs/how-to/spa.md +120 -0
  97. package/docs/how-to/status.md +63 -0
  98. package/docs/how-to/suspense.md +132 -0
  99. package/docs/how-to/using-handle.md +117 -0
  100. package/docs/how-to/view-transitions.md +237 -0
  101. package/docs/how-to/webhook.md +50 -0
  102. package/docs/index.md +39 -0
  103. package/docs/start/data/actions.md +138 -0
  104. package/docs/start/data/custom.md +198 -0
  105. package/docs/start/data/data-loading.md +44 -0
  106. package/docs/start/data/index.md +4 -0
  107. package/docs/start/data/installation.md +52 -0
  108. package/docs/start/data/navigating.md +12 -0
  109. package/docs/start/data/pending-ui.md +12 -0
  110. package/docs/start/data/route-object.md +268 -0
  111. package/docs/start/data/routing.md +281 -0
  112. package/docs/start/data/testing.md +8 -0
  113. package/docs/start/declarative/index.md +4 -0
  114. package/docs/start/declarative/installation.md +43 -0
  115. package/docs/start/declarative/navigating.md +133 -0
  116. package/docs/start/declarative/routing.md +237 -0
  117. package/docs/start/declarative/url-values.md +65 -0
  118. package/docs/start/framework/actions.md +174 -0
  119. package/docs/start/framework/data-loading.md +201 -0
  120. package/docs/start/framework/deploying.md +96 -0
  121. package/docs/start/framework/index.md +4 -0
  122. package/docs/start/framework/installation.md +41 -0
  123. package/docs/start/framework/navigating.md +182 -0
  124. package/docs/start/framework/pending-ui.md +142 -0
  125. package/docs/start/framework/rendering.md +59 -0
  126. package/docs/start/framework/route-module.md +527 -0
  127. package/docs/start/framework/routing.md +362 -0
  128. package/docs/start/framework/testing.md +133 -0
  129. package/docs/start/index.md +4 -0
  130. package/docs/start/modes.md +201 -0
  131. package/docs/upgrading/component-routes.md +363 -0
  132. package/docs/upgrading/future.md +280 -0
  133. package/docs/upgrading/index.md +4 -0
  134. package/docs/upgrading/remix.md +403 -0
  135. package/docs/upgrading/router-provider.md +442 -0
  136. package/docs/upgrading/v6.md +382 -0
  137. package/package.json +2 -1
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: URL Values
3
+ ---
4
+
5
+ # URL Values
6
+
7
+ [MODES: declarative]
8
+
9
+ ## Route Params
10
+
11
+ Route params are the parsed values from a dynamic segment.
12
+
13
+ ```tsx
14
+ <Route path="/concerts/:city" element={<City />} />
15
+ ```
16
+
17
+ In this case, `:city` is the dynamic segment. The parsed value for that city will be available from `useParams`
18
+
19
+ ```tsx
20
+ import { useParams } from "react-router";
21
+
22
+ function City() {
23
+ let { city } = useParams();
24
+ let data = useFakeDataLibrary(`/api/v2/cities/${city}`);
25
+ // ...
26
+ }
27
+ ```
28
+
29
+ ## URL Search Params
30
+
31
+ Search params are the values after a `?` in the URL. They are accessible from `useSearchParams`, which returns an instance of [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
32
+
33
+ ```tsx
34
+ function SearchResults() {
35
+ let [searchParams] = useSearchParams();
36
+ return (
37
+ <div>
38
+ <p>
39
+ You searched for <i>{searchParams.get("q")}</i>
40
+ </p>
41
+ <FakeSearchResults />
42
+ </div>
43
+ );
44
+ }
45
+ ```
46
+
47
+ ## Location Object
48
+
49
+ React Router creates a custom `location` object with some useful information on it accessible with `useLocation`.
50
+
51
+ ```tsx
52
+ function useAnalytics() {
53
+ let location = useLocation();
54
+ useEffect(() => {
55
+ sendFakeAnalytics(location.pathname);
56
+ }, [location]);
57
+ }
58
+
59
+ function useScrollRestoration() {
60
+ let location = useLocation();
61
+ useEffect(() => {
62
+ fakeRestoreScroll(location.key);
63
+ }, [location]);
64
+ }
65
+ ```
@@ -0,0 +1,174 @@
1
+ ---
2
+ title: Actions
3
+ order: 6
4
+ ---
5
+
6
+ # Actions
7
+
8
+ [MODES: framework]
9
+
10
+ ## Introduction
11
+
12
+ Data mutations are done through Route actions. When the action completes, all loader data on the page is revalidated to keep your UI in sync with the data without writing any code to do it.
13
+
14
+ Route actions defined with `action` are only called on the server while actions defined with `clientAction` are run in the browser.
15
+
16
+ ## Client Actions
17
+
18
+ Client actions only run in the browser and take priority over a server action when both are defined.
19
+
20
+ ```tsx filename=app/project.tsx
21
+ // route('/projects/:projectId', './project.tsx')
22
+ import type { Route } from "./+types/project";
23
+ import { Form } from "react-router";
24
+ import { someApi } from "./api";
25
+
26
+ export async function clientAction({
27
+ request,
28
+ }: Route.ClientActionArgs) {
29
+ let formData = await request.formData();
30
+ let title = formData.get("title");
31
+ let project = await someApi.updateProject({ title });
32
+ return project;
33
+ }
34
+
35
+ export default function Project({
36
+ actionData,
37
+ }: Route.ComponentProps) {
38
+ return (
39
+ <div>
40
+ <h1>Project</h1>
41
+ <Form method="post">
42
+ <input type="text" name="title" />
43
+ <button type="submit">Submit</button>
44
+ </Form>
45
+ {actionData ? (
46
+ <p>{actionData.title} updated</p>
47
+ ) : null}
48
+ </div>
49
+ );
50
+ }
51
+ ```
52
+
53
+ ## Server Actions
54
+
55
+ Server actions only run on the server and are removed from client bundles.
56
+
57
+ ```tsx filename=app/project.tsx
58
+ // route('/projects/:projectId', './project.tsx')
59
+ import type { Route } from "./+types/project";
60
+ import { Form } from "react-router";
61
+ import { fakeDb } from "../db";
62
+
63
+ export async function action({
64
+ request,
65
+ }: Route.ActionArgs) {
66
+ let formData = await request.formData();
67
+ let title = formData.get("title");
68
+ let project = await fakeDb.updateProject({ title });
69
+ return project;
70
+ }
71
+
72
+ export default function Project({
73
+ actionData,
74
+ }: Route.ComponentProps) {
75
+ return (
76
+ <div>
77
+ <h1>Project</h1>
78
+ <Form method="post">
79
+ <input type="text" name="title" />
80
+ <button type="submit">Submit</button>
81
+ </Form>
82
+ {actionData ? (
83
+ <p>{actionData.title} updated</p>
84
+ ) : null}
85
+ </div>
86
+ );
87
+ }
88
+ ```
89
+
90
+ ## Calling Actions
91
+
92
+ Actions are called declaratively through `<Form>` and imperatively through `useSubmit` (or `<fetcher.Form>` and `fetcher.submit`) by referencing the route's path and a "post" method.
93
+
94
+ ### Calling actions with a Form
95
+
96
+ ```tsx
97
+ import { Form } from "react-router";
98
+
99
+ function SomeComponent() {
100
+ return (
101
+ <Form action="/projects/123" method="post">
102
+ <input type="text" name="title" />
103
+ <button type="submit">Submit</button>
104
+ </Form>
105
+ );
106
+ }
107
+ ```
108
+
109
+ This will cause a navigation and a new entry will be added to the browser history.
110
+
111
+ ### Calling actions with useSubmit
112
+
113
+ You can submit form data to an action imperatively with `useSubmit`.
114
+
115
+ ```tsx
116
+ import { useCallback } from "react";
117
+ import { useSubmit } from "react-router";
118
+ import { useFakeTimer } from "fake-lib";
119
+
120
+ function useQuizTimer() {
121
+ let submit = useSubmit();
122
+
123
+ let cb = useCallback(() => {
124
+ submit(
125
+ { quizTimedOut: true },
126
+ { action: "/end-quiz", method: "post" },
127
+ );
128
+ }, []);
129
+
130
+ let tenMinutes = 10 * 60 * 1000;
131
+ useFakeTimer(tenMinutes, cb);
132
+ }
133
+ ```
134
+
135
+ This will cause a navigation and a new entry will be added to the browser history.
136
+
137
+ ### Calling actions with a fetcher
138
+
139
+ Fetchers allow you to submit data to actions (and loaders) without causing a navigation (no new entries in the browser history).
140
+
141
+ ```tsx
142
+ import { useFetcher } from "react-router";
143
+
144
+ function Task() {
145
+ let fetcher = useFetcher();
146
+ let busy = fetcher.state !== "idle";
147
+
148
+ return (
149
+ <fetcher.Form method="post" action="/update-task/123">
150
+ <input type="text" name="title" />
151
+ <button type="submit">
152
+ {busy ? "Saving..." : "Save"}
153
+ </button>
154
+ </fetcher.Form>
155
+ );
156
+ }
157
+ ```
158
+
159
+ They also have the imperative `submit` method.
160
+
161
+ ```tsx
162
+ fetcher.submit(
163
+ { title: "New Title" },
164
+ { action: "/update-task/123", method: "post" },
165
+ );
166
+ ```
167
+
168
+ See the [Using Fetchers][fetchers] guide for more information.
169
+
170
+ ---
171
+
172
+ Next: [Navigating](./navigating)
173
+
174
+ [fetchers]: ../../how-to/fetchers
@@ -0,0 +1,201 @@
1
+ ---
2
+ title: Data Loading
3
+ order: 5
4
+ ---
5
+
6
+ # Data Loading
7
+
8
+ [MODES: framework]
9
+
10
+ ## Introduction
11
+
12
+ Data is provided to the route component from `loader` and `clientLoader`.
13
+
14
+ Loader data is automatically serialized from loaders and deserialized in components. In addition to primitive values like strings and numbers, loaders can return promises, maps, sets, dates and more.
15
+
16
+ The type for the `loaderData` prop is [automatically generated][type-safety].
17
+
18
+ <docs-info>We try to support the same set of [serializable types][serializable-types] that React permits server components to pass as props to client components. This future proofs your application for any eventual migration to [RSC][rsc].</docs-info>
19
+
20
+ ## Client Data Loading
21
+
22
+ `clientLoader` is used to fetch data on the client. This is useful for pages or full projects that you'd prefer to fetch data from the browser only.
23
+
24
+ ```tsx filename=app/product.tsx
25
+ // route("products/:pid", "./product.tsx");
26
+ import type { Route } from "./+types/product";
27
+
28
+ export async function clientLoader({
29
+ params,
30
+ }: Route.ClientLoaderArgs) {
31
+ const res = await fetch(`/api/products/${params.pid}`);
32
+ const product = await res.json();
33
+ return product;
34
+ }
35
+
36
+ // HydrateFallback is rendered while the client loader is running
37
+ export function HydrateFallback() {
38
+ return <div>Loading...</div>;
39
+ }
40
+
41
+ export default function Product({
42
+ loaderData,
43
+ }: Route.ComponentProps) {
44
+ const { name, description } = loaderData;
45
+ return (
46
+ <div>
47
+ <h1>{name}</h1>
48
+ <p>{description}</p>
49
+ </div>
50
+ );
51
+ }
52
+ ```
53
+
54
+ ## Server Data Loading
55
+
56
+ When server rendering, `loader` is used for both initial page loads and client navigations. Client navigations call the loader through an automatic `fetch` by React Router from the browser to your server.
57
+
58
+ ```tsx filename=app/product.tsx
59
+ // route("products/:pid", "./product.tsx");
60
+ import type { Route } from "./+types/product";
61
+ import { fakeDb } from "../db";
62
+
63
+ export async function loader({ params }: Route.LoaderArgs) {
64
+ const product = await fakeDb.getProduct(params.pid);
65
+ return product;
66
+ }
67
+
68
+ export default function Product({
69
+ loaderData,
70
+ }: Route.ComponentProps) {
71
+ const { name, description } = loaderData;
72
+ return (
73
+ <div>
74
+ <h1>{name}</h1>
75
+ <p>{description}</p>
76
+ </div>
77
+ );
78
+ }
79
+ ```
80
+
81
+ Note that the `loader` function is removed from client bundles so you can use server only APIs without worrying about them being included in the browser.
82
+
83
+ ## Static Data Loading
84
+
85
+ When pre-rendering, loaders are used to fetch data during the production build.
86
+
87
+ ```tsx filename=app/product.tsx
88
+ // route("products/:pid", "./product.tsx");
89
+ import type { Route } from "./+types/product";
90
+
91
+ export async function loader({ params }: Route.LoaderArgs) {
92
+ let product = await getProductFromCSVFile(params.pid);
93
+ return product;
94
+ }
95
+
96
+ export default function Product({
97
+ loaderData,
98
+ }: Route.ComponentProps) {
99
+ const { name, description } = loaderData;
100
+ return (
101
+ <div>
102
+ <h1>{name}</h1>
103
+ <p>{description}</p>
104
+ </div>
105
+ );
106
+ }
107
+ ```
108
+
109
+ The URLs to pre-render are specified in `react-router.config.ts`:
110
+
111
+ ```ts filename=react-router.config.ts
112
+ import type { Config } from "@react-router/dev/config";
113
+
114
+ export default {
115
+ async prerender() {
116
+ let products = await readProductsFromCSVFile();
117
+ return products.map(
118
+ (product) => `/products/${product.id}`,
119
+ );
120
+ },
121
+ } satisfies Config;
122
+ ```
123
+
124
+ Note that when server rendering, any URLs that aren't pre-rendered will be server rendered as usual, allowing you to pre-render some data at a single route while still server rendering the rest.
125
+
126
+ ## Using Both Loaders
127
+
128
+ `loader` and `clientLoader` can be used together. The `loader` will be used on the server for initial SSR (or pre-rendering) and the `clientLoader` will be used on subsequent client-side navigations.
129
+
130
+ ```tsx filename=app/product.tsx
131
+ // route("products/:pid", "./product.tsx");
132
+ import type { Route } from "./+types/product";
133
+ import { fakeDb } from "../db";
134
+
135
+ export async function loader({ params }: Route.LoaderArgs) {
136
+ return fakeDb.getProduct(params.pid);
137
+ }
138
+
139
+ export async function clientLoader({
140
+ serverLoader,
141
+ params,
142
+ }: Route.ClientLoaderArgs) {
143
+ const res = await fetch(`/api/products/${params.pid}`);
144
+ const serverData = await serverLoader();
145
+ return { ...serverData, ...(await res.json()) };
146
+ }
147
+
148
+ export default function Product({
149
+ loaderData,
150
+ }: Route.ComponentProps) {
151
+ const { name, description } = loaderData;
152
+
153
+ return (
154
+ <div>
155
+ <h1>{name}</h1>
156
+ <p>{description}</p>
157
+ </div>
158
+ );
159
+ }
160
+ ```
161
+
162
+ You can also force the client loader to run during hydration and before the page renders by setting the `hydrate` property on the function. In this situation you will want to render a `HydrateFallback` component to show a fallback UI while the client loader runs.
163
+
164
+ ```tsx filename=app/product.tsx
165
+ export async function loader() {
166
+ /* ... */
167
+ }
168
+
169
+ export async function clientLoader() {
170
+ /* ... */
171
+ }
172
+
173
+ // force the client loader to run during hydration
174
+ clientLoader.hydrate = true as const; // `as const` for type inference
175
+
176
+ export function HydrateFallback() {
177
+ return <div>Loading...</div>;
178
+ }
179
+
180
+ export default function Product() {
181
+ /* ... */
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ Next: [Actions][actions]
188
+
189
+ See also:
190
+
191
+ - [Streaming with Suspense][streaming]
192
+ - [Client Data][client-data]
193
+ - [Using Fetchers][fetchers]
194
+
195
+ [type-safety]: ../../explanation/type-safety
196
+ [serializable-types]: https://react.dev/reference/rsc/use-client#serializable-types
197
+ [rsc]: ../../how-to/react-server-components
198
+ [actions]: ./actions
199
+ [streaming]: ../../how-to/suspense
200
+ [client-data]: ../../how-to/client-data
201
+ [fetchers]: ../../how-to/fetchers#loading-data
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: Deploying
3
+ order: 10
4
+ ---
5
+
6
+ # Deploying
7
+
8
+ [MODES: framework]
9
+
10
+ ## Introduction
11
+
12
+ React Router can be deployed two ways:
13
+
14
+ - Fullstack Hosting
15
+ - Static Hosting
16
+
17
+ The official [React Router templates](https://github.com/remix-run/react-router-templates) can help you bootstrap an application or be used as a reference for your own application.
18
+
19
+ When deploying to static hosting, you can deploy React Router the same as any other single page application with React.
20
+
21
+ ## Templates
22
+
23
+ After running the `create-react-router` command, make sure to follow the instructions in the README.
24
+
25
+ ### Node.js with Docker
26
+
27
+ ```
28
+ npx create-react-router@latest --template remix-run/react-router-templates/default
29
+ ```
30
+
31
+ - Server Rendering
32
+ - Tailwind CSS
33
+
34
+ The containerized application can be deployed to any platform that supports Docker, including:
35
+
36
+ - AWS ECS
37
+ - Google Cloud Run
38
+ - Azure Container Apps
39
+ - Digital Ocean App Platform
40
+ - Fly.io
41
+ - Railway
42
+
43
+ ### Node with Docker (Custom Server)
44
+
45
+ ```
46
+ npx create-react-router@latest --template remix-run/react-router-templates/node-custom-server
47
+ ```
48
+
49
+ - Server Rendering
50
+ - Tailwind CSS
51
+ - Custom express server for more control
52
+
53
+ The containerized application can be deployed to any platform that supports Docker, including:
54
+
55
+ - AWS ECS
56
+ - Google Cloud Run
57
+ - Azure Container Apps
58
+ - Digital Ocean App Platform
59
+ - Fly.io
60
+ - Railway
61
+
62
+ ### Node with Docker and Postgres
63
+
64
+ ```
65
+ npx create-react-router@latest --template remix-run/react-router-templates/node-postgres
66
+ ```
67
+
68
+ - Server Rendering
69
+ - Postgres Database with Drizzle
70
+ - Tailwind CSS
71
+ - Custom express server for more control
72
+
73
+ The containerized application can be deployed to any platform that supports Docker, including:
74
+
75
+ - AWS ECS
76
+ - Google Cloud Run
77
+ - Azure Container Apps
78
+ - Digital Ocean App Platform
79
+ - Fly.io
80
+ - Railway
81
+
82
+ ### Vercel
83
+
84
+ Vercel maintains their own template for React Router. Checkout the [Vercel Guide](https://vercel.com/templates/react-router/react-router-boilerplate) for more information.
85
+
86
+ ### Cloudflare Workers
87
+
88
+ Cloudflare maintains their own template for React Router. Checkout the [Cloudflare Guide](https://developers.cloudflare.com/workers/framework-guides/web-apps/react-router/) for more information.
89
+
90
+ ### Netlify
91
+
92
+ Netlify maintains their own template for React Router. Checkout the [Netlify Guide](https://docs.netlify.com/build/frameworks/framework-setup-guides/react-router/) for more information.
93
+
94
+ ### EdgeOne Pages
95
+
96
+ EdgeOne Pages maintains their own template for React Router. Checkout the [EdgeOne Pages Guide](https://pages.edgeone.ai/document/framework-react-router) for more information.
@@ -0,0 +1,4 @@
1
+ ---
2
+ title: Framework Mode
3
+ order: 2
4
+ ---
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Installation
3
+ order: 1
4
+ ---
5
+
6
+ # Installation
7
+
8
+ [MODES: framework]
9
+
10
+ ## Introduction
11
+
12
+ Most projects start with a template. Let's use a basic template maintained by React Router:
13
+
14
+ ```shellscript nonumber
15
+ npx create-react-router@latest my-react-router-app
16
+ ```
17
+
18
+ Now change into the new directory and start the app
19
+
20
+ ```shellscript nonumber
21
+ cd my-react-router-app
22
+ npm i
23
+ npm run dev
24
+ ```
25
+
26
+ You can now open your browser to `http://localhost:5173`
27
+
28
+ You can [view the template on GitHub][default-template] to see how to manually set up your project.
29
+
30
+ We also have a number of [ready to deploy templates][react-router-templates] available for you to get started with:
31
+
32
+ ```shellscript nonumber
33
+ npx create-react-router@latest --template remix-run/react-router-templates/<template-name>
34
+ ```
35
+
36
+ ---
37
+
38
+ Next: [Routing](./routing)
39
+
40
+ [default-template]: https://github.com/remix-run/react-router-templates/tree/main/default
41
+ [react-router-templates]: https://github.com/remix-run/react-router-templates