create-react-router 8.0.1 → 8.2.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/CHANGELOG.md +19 -0
- package/dist/agent-skills/react-router/SKILL.md +122 -0
- package/dist/agent-skills/react-router/references/data-mode.md +165 -0
- package/dist/agent-skills/react-router/references/declarative-mode.md +123 -0
- package/dist/agent-skills/react-router/references/framework-mode.md +213 -0
- package/dist/agent-skills/react-router/references/rsc.md +90 -0
- package/dist/cli.js +144 -51
- package/package.json +1 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# `create-react-router`
|
|
2
2
|
|
|
3
|
+
## v8.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Detect `nub` as a supported package manager when creating new projects ([#15276](https://github.com/remix-run/react-router/pull/15276))
|
|
8
|
+
|
|
9
|
+
## v8.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- Add a default-on CLI option to include the official React Router agent skill in generated projects ([#15213](https://github.com/remix-run/react-router/pull/15213))
|
|
14
|
+
- New projects include `.agents/skills/react-router` by default when running with `--yes` or in non-interactive shells
|
|
15
|
+
- Interactive runs prompt to include the skill, defaulting to yes
|
|
16
|
+
- Use `--no-agent-skills` to skip copying the skill
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Use Node's built-in utilities for CLI argument parsing, ANSI-stripping, and child process execution to remove the `arg`, `strip-ansi`, and `execa` dependencies ([#15231](https://github.com/remix-run/react-router/pull/15231))
|
|
21
|
+
|
|
3
22
|
## v8.0.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-router
|
|
3
|
+
description: Build applications with React Router in Framework, Data, Declarative, and unstable RSC modes. Use when configuring routes, route modules, loaders, actions, forms, fetchers, navigation, pending UI, SSR/SPA/pre-rendering, middleware, URL params/search params, or React Router upgrades.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# React Router
|
|
8
|
+
|
|
9
|
+
React Router is mode-specific. Before changing an app, identify the mode, load the matching reference, then read the installed docs for the installed package version.
|
|
10
|
+
|
|
11
|
+
## Identify the Mode
|
|
12
|
+
|
|
13
|
+
Do not apply Framework/Data patterns to a Declarative app unless you are intentionally migrating modes.
|
|
14
|
+
|
|
15
|
+
### Framework Mode
|
|
16
|
+
|
|
17
|
+
Use Framework Mode guidance when you see:
|
|
18
|
+
|
|
19
|
+
- `@react-router/dev` in dependencies
|
|
20
|
+
- `react-router.config.ts`
|
|
21
|
+
- `app/routes.ts`
|
|
22
|
+
- `app/entry.server.tsx` and/or `app/entry.client.tsx` files
|
|
23
|
+
- route modules under `app/routes/`
|
|
24
|
+
- route exports like `loader`, `action`, `clientLoader`, `clientAction`, `ErrorBoundary`, `meta`, `links`, or `headers`
|
|
25
|
+
- imports from `./+types/...`
|
|
26
|
+
- the React Router Vite plugin from `@react-router/dev/vite`
|
|
27
|
+
|
|
28
|
+
Framework examples usually use the default `app/` directory, but check `react-router.config.ts` for a custom `appDirectory` before assuming exact paths.
|
|
29
|
+
|
|
30
|
+
Then read `references/framework-mode.md`.
|
|
31
|
+
|
|
32
|
+
### Data Mode
|
|
33
|
+
|
|
34
|
+
Use Data Mode guidance when you see:
|
|
35
|
+
|
|
36
|
+
- `createBrowserRouter`, `createHashRouter`, `createMemoryRouter`, or `createStaticRouter`
|
|
37
|
+
- `<RouterProvider router={router}>`
|
|
38
|
+
- route objects with properties like `path`, `children`, `loader`, `action`, `Component`, `ErrorBoundary`, or `lazy`
|
|
39
|
+
- data APIs without the Framework Vite plugin
|
|
40
|
+
|
|
41
|
+
Then read `references/data-mode.md`.
|
|
42
|
+
|
|
43
|
+
### Declarative Mode
|
|
44
|
+
|
|
45
|
+
Use Declarative Mode guidance when you see:
|
|
46
|
+
|
|
47
|
+
- `<BrowserRouter>`, `<HashRouter>`, or `<MemoryRouter>`
|
|
48
|
+
- `<Routes>` and `<Route>` JSX route configuration
|
|
49
|
+
- route components passed with `element={<Component />}`
|
|
50
|
+
- no data router, no route module convention, and no loaders/actions
|
|
51
|
+
|
|
52
|
+
Then read `references/declarative-mode.md`.
|
|
53
|
+
|
|
54
|
+
### RSC Framework and RSC Data Modes
|
|
55
|
+
|
|
56
|
+
React Server Components support is unstable and exists in both Framework and Data variants. Use RSC guidance when you see:
|
|
57
|
+
|
|
58
|
+
- `unstable_reactRouterRSC`
|
|
59
|
+
- `@vitejs/plugin-rsc`
|
|
60
|
+
- `unstable_RSCRouteConfig`
|
|
61
|
+
- RSC entry files such as `entry.rsc`
|
|
62
|
+
- `ServerComponent`, `ServerErrorBoundary`, `ServerLayout`, or `ServerHydrateFallback`
|
|
63
|
+
- React directives or boundary packages such as `"use client"`, `"server-only"`, or `"client-only"`
|
|
64
|
+
|
|
65
|
+
For RSC Framework, read both `references/framework-mode.md` and `references/rsc.md`.
|
|
66
|
+
For RSC Data, read both `references/data-mode.md` and `references/rsc.md`.
|
|
67
|
+
|
|
68
|
+
## Use Installed Docs as Source of Truth
|
|
69
|
+
|
|
70
|
+
React Router ships markdown docs in the package so guidance can match the installed version:
|
|
71
|
+
|
|
72
|
+
```txt
|
|
73
|
+
node_modules/react-router/docs/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Key docs paths:
|
|
77
|
+
|
|
78
|
+
```txt
|
|
79
|
+
node_modules/react-router/docs/index.md
|
|
80
|
+
node_modules/react-router/docs/start/
|
|
81
|
+
node_modules/react-router/docs/how-to/
|
|
82
|
+
node_modules/react-router/docs/explanation/
|
|
83
|
+
node_modules/react-router/docs/upgrading/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
When this skill references `react-router/docs/...`, read the matching file under `node_modules/react-router/docs/`. If the installed version does not include local docs, use the repo `docs/` directory when working inside the React Router repository; in a consuming app, fall back to version-matched website docs.
|
|
87
|
+
|
|
88
|
+
Most docs include a mode marker near the top:
|
|
89
|
+
|
|
90
|
+
```txt
|
|
91
|
+
[MODES: framework, data, declarative]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Only apply a doc when its mode marker matches the app mode. If a task spans modes, prefer the section or file that matches the current app.
|
|
95
|
+
|
|
96
|
+
RSC is documented primarily in:
|
|
97
|
+
|
|
98
|
+
```txt
|
|
99
|
+
node_modules/react-router/docs/how-to/react-server-components.md
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Skill References
|
|
103
|
+
|
|
104
|
+
Load the relevant reference after identifying the mode:
|
|
105
|
+
|
|
106
|
+
| Reference | Use When |
|
|
107
|
+
| -------------------------------- | --------------------------------------------- |
|
|
108
|
+
| `references/framework-mode.md` | Framework Mode or RSC Framework base behavior |
|
|
109
|
+
| `references/data-mode.md` | Data Mode or RSC Data base behavior |
|
|
110
|
+
| `references/declarative-mode.md` | Declarative Mode |
|
|
111
|
+
| `references/rsc.md` | Any unstable RSC app |
|
|
112
|
+
|
|
113
|
+
## Mode Migration Doc Index
|
|
114
|
+
|
|
115
|
+
If the user explicitly asks to switch modes, read the target mode reference plus the migration-relevant docs:
|
|
116
|
+
|
|
117
|
+
| Migration | Docs to read |
|
|
118
|
+
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
+
| Declarative → Data | `react-router/docs/start/modes.md`, `react-router/docs/start/data/routing.md`, `react-router/docs/start/data/data-loading.md`, `react-router/docs/start/data/actions.md` |
|
|
120
|
+
| Declarative/Data → Framework | `react-router/docs/start/modes.md`, `react-router/docs/start/framework/routing.md`, `react-router/docs/start/framework/route-module.md`, `react-router/docs/how-to/route-module-type-safety.md` |
|
|
121
|
+
| Framework SPA/SSR/pre-render changes | `react-router/docs/start/framework/rendering.md`, `react-router/docs/how-to/spa.md`, `react-router/docs/how-to/pre-rendering.md`, `react-router/docs/start/framework/data-loading.md`, `react-router/docs/start/framework/actions.md` |
|
|
122
|
+
| Future flags/upgrades | `react-router/docs/upgrading/future.md` and relevant files under `react-router/docs/upgrading/` |
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Data Mode
|
|
2
|
+
|
|
3
|
+
Data Mode uses data routers such as `createBrowserRouter` and renders with `<RouterProvider>`. It gives an app route objects, loaders, actions, pending UI, fetchers, and SSR primitives without adopting the Framework Vite plugin or route-module file conventions.
|
|
4
|
+
|
|
5
|
+
Use this reference after the main skill identifies a Data Mode app.
|
|
6
|
+
|
|
7
|
+
## Read the Local Docs by Mode
|
|
8
|
+
|
|
9
|
+
Start with:
|
|
10
|
+
|
|
11
|
+
```txt
|
|
12
|
+
react-router/docs/start/modes.md
|
|
13
|
+
react-router/docs/start/data/index.md
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then use the Data docs under:
|
|
17
|
+
|
|
18
|
+
```txt
|
|
19
|
+
react-router/docs/start/data/
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Those files cover installation, route objects, routing, data loading, actions, navigation, pending UI, and testing. For task-specific details, read relevant files in:
|
|
23
|
+
|
|
24
|
+
```txt
|
|
25
|
+
react-router/docs/how-to/
|
|
26
|
+
react-router/docs/explanation/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Always check the `[MODES: data, ...]` marker in a doc before applying it.
|
|
30
|
+
|
|
31
|
+
## Data Router Shape
|
|
32
|
+
|
|
33
|
+
Typical setup:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { createBrowserRouter, RouterProvider } from "react-router";
|
|
37
|
+
|
|
38
|
+
const router = createBrowserRouter([
|
|
39
|
+
{
|
|
40
|
+
path: "/",
|
|
41
|
+
Component: Root,
|
|
42
|
+
loader: rootLoader,
|
|
43
|
+
children: [
|
|
44
|
+
{ index: true, Component: Home },
|
|
45
|
+
{
|
|
46
|
+
path: "projects/:projectId",
|
|
47
|
+
Component: Project,
|
|
48
|
+
loader: projectLoader,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
root.render(<RouterProvider router={router} />);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Look for route object arrays and APIs such as:
|
|
58
|
+
|
|
59
|
+
- `createBrowserRouter`
|
|
60
|
+
- `createHashRouter`
|
|
61
|
+
- `createMemoryRouter`
|
|
62
|
+
- `RouterProvider`
|
|
63
|
+
- `loader`
|
|
64
|
+
- `action`
|
|
65
|
+
- `Component`
|
|
66
|
+
- `ErrorBoundary`
|
|
67
|
+
- `lazy`
|
|
68
|
+
- `children`
|
|
69
|
+
|
|
70
|
+
## Route Objects and Routing
|
|
71
|
+
|
|
72
|
+
Before editing route configuration, read:
|
|
73
|
+
|
|
74
|
+
```txt
|
|
75
|
+
react-router/docs/start/data/routing.md
|
|
76
|
+
react-router/docs/start/data/route-object.md
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Rules:
|
|
80
|
+
|
|
81
|
+
- Keep route objects outside render when possible.
|
|
82
|
+
- Use nested routes for shared layouts and data boundaries.
|
|
83
|
+
- Use index routes for default child content.
|
|
84
|
+
- Use dynamic segments and splats according to route-object docs.
|
|
85
|
+
- Prefer `Component`/`ErrorBoundary` route object properties in Data Mode examples unless the existing app uses `element` consistently.
|
|
86
|
+
|
|
87
|
+
## Data and Mutations
|
|
88
|
+
|
|
89
|
+
Before working on data loading or mutations, read:
|
|
90
|
+
|
|
91
|
+
```txt
|
|
92
|
+
react-router/docs/start/data/data-loading.md
|
|
93
|
+
react-router/docs/start/data/actions.md
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Rules:
|
|
97
|
+
|
|
98
|
+
- Load route data with route `loader` functions.
|
|
99
|
+
- Mutate route data with route `action` functions.
|
|
100
|
+
- Prefer loaders/actions over route-level `useEffect` fetching.
|
|
101
|
+
- Use `request`, `params`, and returned/throwable Responses as described in the docs.
|
|
102
|
+
- Let React Router revalidate after actions unless there is a documented reason to customize revalidation.
|
|
103
|
+
|
|
104
|
+
Common patterns:
|
|
105
|
+
|
|
106
|
+
- Validation failure from an action: return `data({ errors, values }, { status: 400 })`, then render errors with `useActionData()` or `fetcher.data`.
|
|
107
|
+
- Missing record in a loader: throw `data("Not Found", { status: 404 })` and render the route `ErrorBoundary`.
|
|
108
|
+
- Search/filter data: parse `new URL(request.url).searchParams` in the loader so the URL is shareable and bookmarkable.
|
|
109
|
+
|
|
110
|
+
## Forms, Fetchers, and Pending UI
|
|
111
|
+
|
|
112
|
+
For forms and pending UI, read:
|
|
113
|
+
|
|
114
|
+
```txt
|
|
115
|
+
react-router/docs/start/data/actions.md
|
|
116
|
+
react-router/docs/start/data/pending-ui.md
|
|
117
|
+
react-router/docs/how-to/fetchers.md
|
|
118
|
+
react-router/docs/explanation/form-vs-fetcher.md
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Rules of thumb:
|
|
122
|
+
|
|
123
|
+
- Search/filter form that updates the URL: `<Form method="get">`.
|
|
124
|
+
- Mutation that should change URL/history or redirect after completion: `<Form method="post">`.
|
|
125
|
+
- Mutation that should keep the user on the same page: `useFetcher` / `<fetcher.Form>`.
|
|
126
|
+
- Optimistic UI: derive from `fetcher.formData` or `navigation.formData`.
|
|
127
|
+
|
|
128
|
+
## Navigation and URL State
|
|
129
|
+
|
|
130
|
+
Before changing navigation or search params, read:
|
|
131
|
+
|
|
132
|
+
```txt
|
|
133
|
+
react-router/docs/start/data/navigating.md
|
|
134
|
+
react-router/docs/how-to/search-params.md
|
|
135
|
+
react-router/docs/explanation/location.md
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Rules:
|
|
139
|
+
|
|
140
|
+
- Use `<Link>`/`<NavLink>` for user-initiated internal navigation.
|
|
141
|
+
- Use `redirect` in loaders/actions when navigation follows data loading or mutations.
|
|
142
|
+
- Use `useNavigate` for imperative client-side event navigation.
|
|
143
|
+
- Treat URL params as strings and validate/parse them.
|
|
144
|
+
- Preserve unrelated search params unless intentionally resetting them.
|
|
145
|
+
|
|
146
|
+
## SSR in Data Mode
|
|
147
|
+
|
|
148
|
+
Data Mode SSR is manual and lower-level than Framework Mode. Before implementing or changing SSR, read the Data Mode custom/SSR docs and match existing server abstractions.
|
|
149
|
+
|
|
150
|
+
Start with:
|
|
151
|
+
|
|
152
|
+
```txt
|
|
153
|
+
react-router/docs/start/data/custom.md
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Look for APIs like `createStaticHandler`, `createStaticRouter`, `StaticRouterProvider`, and hydration data handling in the current app before changing anything.
|
|
157
|
+
|
|
158
|
+
## RSC Data
|
|
159
|
+
|
|
160
|
+
If this Data Mode app uses `unstable_RSCRouteConfig`, RSC route config, or low-level RSC server APIs, also read:
|
|
161
|
+
|
|
162
|
+
```txt
|
|
163
|
+
references/rsc.md
|
|
164
|
+
react-router/docs/how-to/react-server-components.md
|
|
165
|
+
```
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Declarative Mode
|
|
2
|
+
|
|
3
|
+
Declarative Mode is React Router's simplest mode. It uses router components like `<BrowserRouter>` and JSX routes with `<Routes>`/`<Route>`. It does not provide loaders, actions, fetchers, or data-router pending UI.
|
|
4
|
+
|
|
5
|
+
Use this reference after the main skill identifies a Declarative Mode app.
|
|
6
|
+
|
|
7
|
+
## Read the Local Docs by Mode
|
|
8
|
+
|
|
9
|
+
Start with:
|
|
10
|
+
|
|
11
|
+
```txt
|
|
12
|
+
react-router/docs/start/modes.md
|
|
13
|
+
react-router/docs/start/declarative/index.md
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then use the Declarative docs under:
|
|
17
|
+
|
|
18
|
+
```txt
|
|
19
|
+
react-router/docs/start/declarative/
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Those files cover installation, routing, navigation, and URL values. For conceptual details, read relevant files in:
|
|
23
|
+
|
|
24
|
+
```txt
|
|
25
|
+
react-router/docs/explanation/
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Always check the `[MODES: declarative, ...]` marker in a doc before applying it.
|
|
29
|
+
|
|
30
|
+
## Declarative Router Shape
|
|
31
|
+
|
|
32
|
+
Typical setup:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { BrowserRouter, Routes, Route } from "react-router";
|
|
36
|
+
|
|
37
|
+
function App() {
|
|
38
|
+
return (
|
|
39
|
+
<BrowserRouter>
|
|
40
|
+
<Routes>
|
|
41
|
+
<Route path="/" element={<Home />} />
|
|
42
|
+
<Route path="about" element={<About />} />
|
|
43
|
+
<Route path="dashboard" element={<DashboardLayout />}>
|
|
44
|
+
<Route index element={<DashboardHome />} />
|
|
45
|
+
<Route path="settings" element={<Settings />} />
|
|
46
|
+
</Route>
|
|
47
|
+
</Routes>
|
|
48
|
+
</BrowserRouter>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Look for APIs such as:
|
|
54
|
+
|
|
55
|
+
- `<BrowserRouter>`
|
|
56
|
+
- `<HashRouter>`
|
|
57
|
+
- `<MemoryRouter>`
|
|
58
|
+
- `<Routes>`
|
|
59
|
+
- `<Route>`
|
|
60
|
+
- `element={<Component />}`
|
|
61
|
+
- `useRoutes`
|
|
62
|
+
|
|
63
|
+
## Routing
|
|
64
|
+
|
|
65
|
+
Before editing routes, read:
|
|
66
|
+
|
|
67
|
+
```txt
|
|
68
|
+
react-router/docs/start/declarative/routing.md
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Rules:
|
|
72
|
+
|
|
73
|
+
- Use `<Routes>` and `<Route>` for route configuration.
|
|
74
|
+
- Use nested routes with `<Outlet>` for shared layout.
|
|
75
|
+
- Use index routes for default child UI.
|
|
76
|
+
- Use route params and splats according to the declarative routing docs.
|
|
77
|
+
- Do not add route object loaders/actions to a Declarative router.
|
|
78
|
+
|
|
79
|
+
## Navigation
|
|
80
|
+
|
|
81
|
+
Before changing navigation, read:
|
|
82
|
+
|
|
83
|
+
```txt
|
|
84
|
+
react-router/docs/start/declarative/navigating.md
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Rules:
|
|
88
|
+
|
|
89
|
+
- Use `<Link>` or `<NavLink>` for user-initiated internal navigation.
|
|
90
|
+
- Use `NavLink` when active styling matters.
|
|
91
|
+
- Use `useNavigate` for imperative navigation from event handlers or effects.
|
|
92
|
+
- Do not use plain `<a href>` for internal navigation unless intentionally forcing a full document navigation.
|
|
93
|
+
|
|
94
|
+
## URL Values
|
|
95
|
+
|
|
96
|
+
Before changing params, search params, or location state, read:
|
|
97
|
+
|
|
98
|
+
```txt
|
|
99
|
+
react-router/docs/start/declarative/url-values.md
|
|
100
|
+
react-router/docs/explanation/location.md
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Rules:
|
|
104
|
+
|
|
105
|
+
- Use `useParams` for dynamic route params.
|
|
106
|
+
- Use `useSearchParams` for query string state.
|
|
107
|
+
- Use `useLocation` for the current location object and navigation state.
|
|
108
|
+
- Validate and parse URL params; they are strings and can be absent.
|
|
109
|
+
- Preserve unrelated search params unless intentionally resetting them.
|
|
110
|
+
|
|
111
|
+
## Mode Boundary
|
|
112
|
+
|
|
113
|
+
Declarative Mode does not have Data/Framework APIs such as:
|
|
114
|
+
|
|
115
|
+
- `loader`
|
|
116
|
+
- `action`
|
|
117
|
+
- `<Form>`
|
|
118
|
+
- `useFetcher`
|
|
119
|
+
- `useNavigation`
|
|
120
|
+
- route module exports
|
|
121
|
+
- generated `./+types` route types
|
|
122
|
+
|
|
123
|
+
If the user asks for route data loading, DB/API-backed data, CRUD, form mutations, validation returned from submissions, revalidation, pending UI, optimistic UI, or fetchers, recommend Data Mode or Framework Mode depending on how much structure they want. Ask before migrating unless they already requested it.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Framework Mode
|
|
2
|
+
|
|
3
|
+
Framework Mode is React Router's full-stack mode. It uses the React Router Vite plugin, route config in `app/routes.ts`, route modules, generated route types, and rendering strategies such as SSR, SPA mode, and pre-rendering.
|
|
4
|
+
|
|
5
|
+
Use this reference after the main skill identifies a Framework Mode app.
|
|
6
|
+
|
|
7
|
+
## Read the Local Docs by Mode
|
|
8
|
+
|
|
9
|
+
Start with:
|
|
10
|
+
|
|
11
|
+
```txt
|
|
12
|
+
react-router/docs/start/modes.md
|
|
13
|
+
react-router/docs/start/framework/index.md
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then use the Framework docs under:
|
|
17
|
+
|
|
18
|
+
```txt
|
|
19
|
+
react-router/docs/start/framework/
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Those files cover installation, routing, route modules, data loading, actions, navigation, pending UI, rendering, deploying, and testing. For task-specific details, read relevant files in:
|
|
23
|
+
|
|
24
|
+
```txt
|
|
25
|
+
react-router/docs/how-to/
|
|
26
|
+
react-router/docs/explanation/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Always check the `[MODES: framework, ...]` marker in a doc before applying it.
|
|
30
|
+
|
|
31
|
+
## Framework Shape
|
|
32
|
+
|
|
33
|
+
Examples usually assume the default `appDirectory` of `app`. Check `react-router.config.ts` before assuming exact paths.
|
|
34
|
+
|
|
35
|
+
Look for these files and conventions:
|
|
36
|
+
|
|
37
|
+
```txt
|
|
38
|
+
react-router.config.ts
|
|
39
|
+
app/root.tsx
|
|
40
|
+
app/routes.ts
|
|
41
|
+
app/routes/**/*.tsx
|
|
42
|
+
route modules importing from ./+types/...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Typical route module:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import type { Route } from "./+types/product";
|
|
49
|
+
|
|
50
|
+
export async function loader({ params }: Route.LoaderArgs) {
|
|
51
|
+
return { product: await getProduct(params.productId) };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default function Product({ loaderData }: Route.ComponentProps) {
|
|
55
|
+
return <h1>{loaderData.product.name}</h1>;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Route Configuration
|
|
60
|
+
|
|
61
|
+
Framework apps use `app/routes.ts`. Many apps use file-system routing via `flatRoutes()`, but manual route config is also supported.
|
|
62
|
+
|
|
63
|
+
Before editing routes, read:
|
|
64
|
+
|
|
65
|
+
```txt
|
|
66
|
+
react-router/docs/start/framework/routing.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
If the app uses file-route conventions, read:
|
|
70
|
+
|
|
71
|
+
```txt
|
|
72
|
+
react-router/docs/how-to/file-route-conventions.md
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Route Modules
|
|
76
|
+
|
|
77
|
+
Route modules are the main unit of Framework Mode. Before adding or changing route exports, read:
|
|
78
|
+
|
|
79
|
+
```txt
|
|
80
|
+
react-router/docs/start/framework/route-module.md
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Common exports include:
|
|
84
|
+
|
|
85
|
+
| Export | Use |
|
|
86
|
+
| --------------------------------- | ------------------------------------------------------------------- |
|
|
87
|
+
| `default` | Route component rendered for the match |
|
|
88
|
+
| `loader` | Server data loading for SSR/pre-rendering/server data requests |
|
|
89
|
+
| `clientLoader` | Browser-only data loading or supplementing server loader data |
|
|
90
|
+
| `action` | Server mutation called by `<Form>`, `useSubmit`, or fetchers |
|
|
91
|
+
| `clientAction` | Browser-only mutation or client-side wrapper around a server action |
|
|
92
|
+
| `ErrorBoundary` | UI for errors thrown by this route's loaders/actions/component |
|
|
93
|
+
| `HydrateFallback` | Initial fallback while client loader hydration runs |
|
|
94
|
+
| `links` / `meta` | Route document links and metadata |
|
|
95
|
+
| `handle` | Arbitrary route metadata consumed via `useMatches` |
|
|
96
|
+
| `shouldRevalidate` | Overrides default loader revalidation behavior |
|
|
97
|
+
| `middleware` / `clientMiddleware` | Server/client request pipeline hooks when enabled |
|
|
98
|
+
|
|
99
|
+
Use generated `Route.*` types from `./+types/<route>` for route module args and props.
|
|
100
|
+
|
|
101
|
+
## Layout and Root Route Rules
|
|
102
|
+
|
|
103
|
+
- `app/root.tsx` is the root route and should contain global document/app shell concerns.
|
|
104
|
+
- Put global providers, app-wide nav, app-wide footer, scripts/meta/links, and document structure in `root.tsx` when appropriate.
|
|
105
|
+
- Use nested routes/layout routes for section-specific layouts.
|
|
106
|
+
- Do not flatten routes that should share UI or data boundaries.
|
|
107
|
+
|
|
108
|
+
Useful docs:
|
|
109
|
+
|
|
110
|
+
```txt
|
|
111
|
+
react-router/docs/explanation/special-files.md
|
|
112
|
+
react-router/docs/start/framework/routing.md
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Data and Mutations
|
|
116
|
+
|
|
117
|
+
Before working on route data:
|
|
118
|
+
|
|
119
|
+
```txt
|
|
120
|
+
react-router/docs/start/framework/data-loading.md
|
|
121
|
+
react-router/docs/start/framework/actions.md
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Framework rules:
|
|
125
|
+
|
|
126
|
+
- Load route data with `loader` or `clientLoader`.
|
|
127
|
+
- Mutate route data with `action` or `clientAction`.
|
|
128
|
+
- Prefer route loaders/actions over ad hoc `useEffect` fetching for route data.
|
|
129
|
+
- Use `data()`/Responses and redirects according to the docs.
|
|
130
|
+
- Let React Router revalidate after actions unless the docs point you to `shouldRevalidate`.
|
|
131
|
+
- In SSR/server data routes, keep Node-only/database code in server-only modules and call it from `loader`/`action`, not from browser-rendered component code.
|
|
132
|
+
|
|
133
|
+
Common patterns:
|
|
134
|
+
|
|
135
|
+
- Validation failure from an action: return `data({ errors, values }, { status: 400 })`, then render errors from `Route.ComponentProps["actionData"]` or `fetcher.data`.
|
|
136
|
+
- Missing record in a loader: throw `data("Not Found", { status: 404 })` and render the route `ErrorBoundary`.
|
|
137
|
+
- Search/filter data: parse the route request URL/search params in the loader so the URL is shareable and bookmarkable.
|
|
138
|
+
|
|
139
|
+
## Forms, Fetchers, and Pending UI
|
|
140
|
+
|
|
141
|
+
For forms and pending UI, read:
|
|
142
|
+
|
|
143
|
+
```txt
|
|
144
|
+
react-router/docs/start/framework/actions.md
|
|
145
|
+
react-router/docs/start/framework/pending-ui.md
|
|
146
|
+
react-router/docs/how-to/fetchers.md
|
|
147
|
+
react-router/docs/explanation/form-vs-fetcher.md
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Rules of thumb:
|
|
151
|
+
|
|
152
|
+
- Search/filter form that updates the URL: `<Form method="get">`.
|
|
153
|
+
- Mutation that should change URL/history or redirect after completion: `<Form method="post">`.
|
|
154
|
+
- Mutation that should keep the user on the same page: `useFetcher` / `<fetcher.Form>`.
|
|
155
|
+
- Optimistic UI: derive from `fetcher.formData` or `navigation.formData`.
|
|
156
|
+
|
|
157
|
+
## Type Safety
|
|
158
|
+
|
|
159
|
+
Before changing generated route types or typed URL behavior, read:
|
|
160
|
+
|
|
161
|
+
```txt
|
|
162
|
+
react-router/docs/how-to/route-module-type-safety.md
|
|
163
|
+
react-router/docs/explanation/type-safety.md
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Rules:
|
|
167
|
+
|
|
168
|
+
- Import types from `./+types/<route>`.
|
|
169
|
+
- Use `Route.LoaderArgs`, `Route.ActionArgs`, `Route.ComponentProps`, etc.
|
|
170
|
+
- Use type-only imports where appropriate.
|
|
171
|
+
- Do not edit generated `.react-router/types` files.
|
|
172
|
+
|
|
173
|
+
## Metadata
|
|
174
|
+
|
|
175
|
+
Before changing `meta`, read:
|
|
176
|
+
|
|
177
|
+
```txt
|
|
178
|
+
react-router/docs/how-to/meta.md
|
|
179
|
+
react-router/docs/start/framework/route-module.md
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Important: `meta` receives `loaderData`; do not use deprecated `data` args.
|
|
183
|
+
|
|
184
|
+
## Rendering Strategy
|
|
185
|
+
|
|
186
|
+
Framework Mode can be SSR, SPA, pre-rendered, or mixed depending on config and route behavior. Before changing rendering behavior, read:
|
|
187
|
+
|
|
188
|
+
```txt
|
|
189
|
+
react-router/docs/start/framework/rendering.md
|
|
190
|
+
react-router/docs/how-to/spa.md
|
|
191
|
+
react-router/docs/how-to/pre-rendering.md
|
|
192
|
+
react-router/docs/explanation/hydration.md
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Middleware, Sessions, and Auth
|
|
196
|
+
|
|
197
|
+
Before implementing middleware or auth/session flows, read:
|
|
198
|
+
|
|
199
|
+
```txt
|
|
200
|
+
react-router/docs/how-to/middleware.md
|
|
201
|
+
react-router/docs/explanation/sessions-and-cookies.md
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Middleware and context APIs are version/config sensitive. Check the installed React Router version and the app's `react-router.config.ts` before implementing.
|
|
205
|
+
|
|
206
|
+
## RSC Framework
|
|
207
|
+
|
|
208
|
+
If this Framework app uses `unstable_reactRouterRSC` or `@vitejs/plugin-rsc`, also read:
|
|
209
|
+
|
|
210
|
+
```txt
|
|
211
|
+
references/rsc.md
|
|
212
|
+
react-router/docs/how-to/react-server-components.md
|
|
213
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# React Server Components (RSC)
|
|
2
|
+
|
|
3
|
+
React Router's RSC support is unstable and exists in two variants:
|
|
4
|
+
|
|
5
|
+
- **RSC Framework Mode**: Framework Mode with the unstable RSC Vite plugin.
|
|
6
|
+
- **RSC Data Mode**: lower-level RSC runtime APIs and manual bundler/server integration.
|
|
7
|
+
|
|
8
|
+
Use this reference in addition to `framework-mode.md` or `data-mode.md` after the main skill identifies an RSC app.
|
|
9
|
+
|
|
10
|
+
## Read the Local RSC Docs
|
|
11
|
+
|
|
12
|
+
Start with:
|
|
13
|
+
|
|
14
|
+
```txt
|
|
15
|
+
react-router/docs/how-to/react-server-components.md
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then read the relevant base mode docs:
|
|
19
|
+
|
|
20
|
+
```txt
|
|
21
|
+
react-router/docs/start/framework/
|
|
22
|
+
react-router/docs/start/data/
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
RSC docs may describe differences from non-RSC mode rather than repeating every Framework/Data concept, so keep both layers in mind.
|
|
26
|
+
|
|
27
|
+
## Detect RSC Framework Mode
|
|
28
|
+
|
|
29
|
+
Look for:
|
|
30
|
+
|
|
31
|
+
- `unstable_reactRouterRSC` imported from `@react-router/dev/vite`
|
|
32
|
+
- `@vitejs/plugin-rsc`
|
|
33
|
+
- `vite.config.ts` with `plugins: [reactRouterRSC(), rsc()]`
|
|
34
|
+
- Framework route modules plus RSC route exports
|
|
35
|
+
- RSC entry files such as `entry.rsc`
|
|
36
|
+
|
|
37
|
+
RSC Framework Mode uses a different Vite plugin from non-RSC Framework Mode. Do not swap it for the regular `reactRouter()` plugin.
|
|
38
|
+
|
|
39
|
+
## Detect RSC Data Mode
|
|
40
|
+
|
|
41
|
+
Look for:
|
|
42
|
+
|
|
43
|
+
- `unstable_RSCRouteConfig`
|
|
44
|
+
- route config passed to lower-level RSC APIs
|
|
45
|
+
- APIs such as `unstable_matchRSCServerRequest`, `unstable_routeRSCServerRequest`, `unstable_RSCHydratedRouter`, or `unstable_RSCStaticRouter`
|
|
46
|
+
- custom bundler/server setup around RSC
|
|
47
|
+
|
|
48
|
+
RSC Data Mode is more manual than RSC Framework Mode. Match the app's bundler and server abstractions before changing routes or entries.
|
|
49
|
+
|
|
50
|
+
## RSC Route Module Differences
|
|
51
|
+
|
|
52
|
+
In RSC Framework Mode, many normal Framework Mode concepts still apply, but routes can use server component exports.
|
|
53
|
+
|
|
54
|
+
Important route-module concepts from the RSC docs include:
|
|
55
|
+
|
|
56
|
+
- `ServerComponent` instead of the usual client `default` component
|
|
57
|
+
- `ServerErrorBoundary` paired with `ErrorBoundary`
|
|
58
|
+
- `ServerLayout` paired with `Layout`
|
|
59
|
+
- `ServerHydrateFallback` paired with `HydrateFallback`
|
|
60
|
+
- server-rendered React elements returned from loaders/actions
|
|
61
|
+
|
|
62
|
+
A route module cannot export both the normal client component and its server component counterpart for the same role. Read the RSC docs before adding these exports.
|
|
63
|
+
|
|
64
|
+
## Client/Server Boundaries
|
|
65
|
+
|
|
66
|
+
RSC code must respect React's client/server split:
|
|
67
|
+
|
|
68
|
+
- Use `"use client"` for components that need hooks, browser APIs, or event handlers.
|
|
69
|
+
- Use server-only modules for server data access and secrets.
|
|
70
|
+
- In RSC Framework Mode, prefer the `server-only` and `client-only` boundary imports described in the docs.
|
|
71
|
+
- Do not assume `.server`/`.client` file naming works the same way in RSC Framework Mode; read the RSC docs before relying on those conventions.
|
|
72
|
+
|
|
73
|
+
## Data Loading in RSC
|
|
74
|
+
|
|
75
|
+
RSC changes where data can be loaded:
|
|
76
|
+
|
|
77
|
+
- Server Components can fetch data directly on the server.
|
|
78
|
+
- Loaders/actions may still exist and can have RSC-specific behavior.
|
|
79
|
+
- Client components still need client-safe data and cannot directly access server-only modules.
|
|
80
|
+
|
|
81
|
+
When choosing between a server component fetch, a loader, and a client loader/action, follow the RSC docs and match existing app patterns.
|
|
82
|
+
|
|
83
|
+
## Stability
|
|
84
|
+
|
|
85
|
+
RSC APIs are explicitly unstable. Before implementing or refactoring RSC code:
|
|
86
|
+
|
|
87
|
+
- Check the installed React Router version.
|
|
88
|
+
- Check the installed `@vitejs/plugin-rsc` version.
|
|
89
|
+
- Read the app's existing RSC entry/config files.
|
|
90
|
+
- Prefer minimal changes that match current patterns.
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* create-react-router v8.0
|
|
3
|
+
* create-react-router v8.2.0
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) Remix Software Inc.
|
|
6
6
|
*
|
|
@@ -10,22 +10,20 @@
|
|
|
10
10
|
* @license MIT
|
|
11
11
|
*/
|
|
12
12
|
import process from "node:process";
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
13
14
|
import fs, { existsSync } from "node:fs";
|
|
14
15
|
import { cp, readFile, readdir, realpath, writeFile } from "node:fs/promises";
|
|
15
16
|
import os from "node:os";
|
|
16
17
|
import path from "node:path";
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
import arg from "arg";
|
|
18
|
+
import url, { fileURLToPath } from "node:url";
|
|
19
|
+
import { parseArgs, promisify, stripVTControlCharacters } from "node:util";
|
|
20
20
|
import * as semver from "semver";
|
|
21
21
|
import sortPackageJSON from "sort-package-json";
|
|
22
22
|
import { beep, cursor, erase } from "sisteransi";
|
|
23
23
|
import EventEmitter from "node:events";
|
|
24
24
|
import readline from "node:readline";
|
|
25
25
|
import pc from "picocolors";
|
|
26
|
-
import url from "node:url";
|
|
27
26
|
import stream from "node:stream";
|
|
28
|
-
import { promisify } from "node:util";
|
|
29
27
|
import gunzip from "gunzip-maybe";
|
|
30
28
|
import tar from "tar-fs";
|
|
31
29
|
//#region utils.ts
|
|
@@ -1239,9 +1237,12 @@ var CopyTemplateError = class extends Error {
|
|
|
1239
1237
|
};
|
|
1240
1238
|
//#endregion
|
|
1241
1239
|
//#region package.json
|
|
1242
|
-
var version = "8.0
|
|
1240
|
+
var version = "8.2.0";
|
|
1243
1241
|
//#endregion
|
|
1244
1242
|
//#region index.ts
|
|
1243
|
+
const currentFileDir = path.dirname(fileURLToPath(import.meta.url));
|
|
1244
|
+
const packageDir = path.basename(currentFileDir) === "dist" ? path.dirname(currentFileDir) : currentFileDir;
|
|
1245
|
+
const agentSkillPath = path.join(packageDir, "dist/agent-skills/react-router");
|
|
1245
1246
|
async function createReactRouter(argv) {
|
|
1246
1247
|
let ctx = await getContext(argv);
|
|
1247
1248
|
if (ctx.help) {
|
|
@@ -1259,6 +1260,8 @@ async function createReactRouter(argv) {
|
|
|
1259
1260
|
copyTempDirToAppDirStep,
|
|
1260
1261
|
gitInitQuestionStep,
|
|
1261
1262
|
installDependenciesQuestionStep,
|
|
1263
|
+
agentSkillsQuestionStep,
|
|
1264
|
+
copyAgentSkillsToAppDirStep,
|
|
1262
1265
|
installDependenciesStep,
|
|
1263
1266
|
gitInitStep,
|
|
1264
1267
|
doneStep
|
|
@@ -1271,33 +1274,48 @@ async function createReactRouter(argv) {
|
|
|
1271
1274
|
}
|
|
1272
1275
|
}
|
|
1273
1276
|
async function getContext(argv) {
|
|
1274
|
-
let
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1277
|
+
let { values, positionals } = parseArgs({
|
|
1278
|
+
args: argv,
|
|
1279
|
+
allowPositionals: true,
|
|
1280
|
+
strict: false,
|
|
1281
|
+
options: {
|
|
1282
|
+
"agent-skills": { type: "boolean" },
|
|
1283
|
+
debug: { type: "boolean" },
|
|
1284
|
+
"git-init": { type: "boolean" },
|
|
1285
|
+
help: {
|
|
1286
|
+
type: "boolean",
|
|
1287
|
+
short: "h"
|
|
1288
|
+
},
|
|
1289
|
+
install: { type: "boolean" },
|
|
1290
|
+
"no-agent-skills": { type: "boolean" },
|
|
1291
|
+
"no-color": { type: "boolean" },
|
|
1292
|
+
"no-git-init": { type: "boolean" },
|
|
1293
|
+
"no-install": { type: "boolean" },
|
|
1294
|
+
"no-motion": { type: "boolean" },
|
|
1295
|
+
overwrite: { type: "boolean" },
|
|
1296
|
+
"package-manager": { type: "string" },
|
|
1297
|
+
"react-router-version": {
|
|
1298
|
+
type: "string",
|
|
1299
|
+
short: "v"
|
|
1300
|
+
},
|
|
1301
|
+
"show-install-output": { type: "boolean" },
|
|
1302
|
+
template: { type: "string" },
|
|
1303
|
+
token: { type: "string" },
|
|
1304
|
+
version: {
|
|
1305
|
+
type: "boolean",
|
|
1306
|
+
short: "V"
|
|
1307
|
+
},
|
|
1308
|
+
yes: {
|
|
1309
|
+
type: "boolean",
|
|
1310
|
+
short: "y"
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1298
1313
|
});
|
|
1299
|
-
let
|
|
1300
|
-
let
|
|
1314
|
+
let getBooleanArg = (value) => typeof value === "boolean" ? value : void 0;
|
|
1315
|
+
let getStringArg = (value) => typeof value === "string" ? value : void 0;
|
|
1316
|
+
let selectedReactRouterVersion = getStringArg(values["react-router-version"]);
|
|
1317
|
+
let yes = getBooleanArg(values.yes);
|
|
1318
|
+
let cwd = positionals[0];
|
|
1301
1319
|
let interactive = isInteractive();
|
|
1302
1320
|
let projectName = cwd;
|
|
1303
1321
|
if (!interactive) yes = true;
|
|
@@ -1309,21 +1327,22 @@ async function getContext(argv) {
|
|
|
1309
1327
|
return {
|
|
1310
1328
|
tempDir: path.join(await realpath(os.tmpdir()), `create-react-router--${Math.random().toString(36).substr(2, 8)}`),
|
|
1311
1329
|
cwd,
|
|
1312
|
-
overwrite,
|
|
1330
|
+
overwrite: getBooleanArg(values.overwrite),
|
|
1313
1331
|
interactive,
|
|
1314
|
-
debug,
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1332
|
+
debug: getBooleanArg(values.debug) ?? false,
|
|
1333
|
+
agentSkills: getBooleanArg(values["agent-skills"]) ?? (getBooleanArg(values["no-agent-skills"]) ? false : yes),
|
|
1334
|
+
git: getBooleanArg(values["git-init"]) ?? (getBooleanArg(values["no-git-init"]) ? false : yes),
|
|
1335
|
+
help: getBooleanArg(values.help) ?? false,
|
|
1336
|
+
install: getBooleanArg(values.install) ?? (getBooleanArg(values["no-install"]) ? false : yes),
|
|
1337
|
+
showInstallOutput: getBooleanArg(values["show-install-output"]) ?? false,
|
|
1338
|
+
noMotion: getBooleanArg(values["no-motion"]),
|
|
1339
|
+
pkgManager: validatePackageManager(getStringArg(values["package-manager"]) ?? detectPackageManager() ?? "npm"),
|
|
1321
1340
|
projectName,
|
|
1322
1341
|
prompt,
|
|
1323
1342
|
reactRouterVersion: selectedReactRouterVersion || version,
|
|
1324
|
-
template,
|
|
1325
|
-
token,
|
|
1326
|
-
versionRequested
|
|
1343
|
+
template: getStringArg(values.template),
|
|
1344
|
+
token: getStringArg(values.token),
|
|
1345
|
+
versionRequested: getBooleanArg(values.version)
|
|
1327
1346
|
};
|
|
1328
1347
|
}
|
|
1329
1348
|
async function introStep(ctx) {
|
|
@@ -1410,6 +1429,46 @@ async function copyTemplateToTempDirStep(ctx) {
|
|
|
1410
1429
|
ctx
|
|
1411
1430
|
});
|
|
1412
1431
|
}
|
|
1432
|
+
async function agentSkillsQuestionStep(ctx) {
|
|
1433
|
+
if (ctx.agentSkills === void 0) {
|
|
1434
|
+
let { agentSkills = true } = await ctx.prompt({
|
|
1435
|
+
name: "agentSkills",
|
|
1436
|
+
type: "confirm",
|
|
1437
|
+
label: title("skill"),
|
|
1438
|
+
message: "Include the React Router agent skill?",
|
|
1439
|
+
hint: "recommended",
|
|
1440
|
+
initial: true
|
|
1441
|
+
});
|
|
1442
|
+
ctx.agentSkills = agentSkills;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
async function copyAgentSkillsToAppDirStep(ctx) {
|
|
1446
|
+
if (!ctx.agentSkills) {
|
|
1447
|
+
await sleep(100);
|
|
1448
|
+
info("Skipping agent skill.", [
|
|
1449
|
+
"You can add it later from ",
|
|
1450
|
+
color.reset("https://github.com/remix-run/react-router/tree/main/.agents/skills/react-router"),
|
|
1451
|
+
"."
|
|
1452
|
+
]);
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
if (!existsSync(path.join(agentSkillPath, "SKILL.md"))) {
|
|
1456
|
+
error("Oh no!", "React Router agent skill files were not found in this package.");
|
|
1457
|
+
throw new Error("React Router agent skill files were not found");
|
|
1458
|
+
}
|
|
1459
|
+
let destPath = path.join(ctx.cwd, ".agents", "skills", "react-router");
|
|
1460
|
+
if (existsSync(destPath)) {
|
|
1461
|
+
info("Agent skill:", "React Router agent skill already included");
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
await ensureDirectory(path.dirname(destPath));
|
|
1465
|
+
await cp(agentSkillPath, destPath, {
|
|
1466
|
+
errorOnExist: true,
|
|
1467
|
+
force: false,
|
|
1468
|
+
recursive: true
|
|
1469
|
+
});
|
|
1470
|
+
info("Agent skill:", "Included React Router agent skill");
|
|
1471
|
+
}
|
|
1413
1472
|
async function copyTempDirToAppDirStep(ctx) {
|
|
1414
1473
|
await ensureDirectory(ctx.cwd);
|
|
1415
1474
|
let files1 = await getDirectoryFilesRecursive(ctx.tempDir);
|
|
@@ -1535,9 +1594,9 @@ async function gitInitStep(ctx) {
|
|
|
1535
1594
|
};
|
|
1536
1595
|
let commitMsg = "Initial commit from create-react-router";
|
|
1537
1596
|
try {
|
|
1538
|
-
await
|
|
1539
|
-
await
|
|
1540
|
-
await
|
|
1597
|
+
await runCommand("git", ["init"], options);
|
|
1598
|
+
await runCommand("git", ["add", "."], options);
|
|
1599
|
+
await runCommand("git", [
|
|
1541
1600
|
"commit",
|
|
1542
1601
|
"-m",
|
|
1543
1602
|
commitMsg
|
|
@@ -1559,12 +1618,12 @@ async function doneStep(ctx) {
|
|
|
1559
1618
|
await sleep(100);
|
|
1560
1619
|
if (projectDir !== "") {
|
|
1561
1620
|
let enter = [`\n${prefix}Enter your project directory using`, color.cyan(`cd .${path.sep}${projectDir}`)];
|
|
1562
|
-
let len = enter[0].length +
|
|
1621
|
+
let len = enter[0].length + stripVTControlCharacters(enter[1]).length;
|
|
1563
1622
|
log(enter.join(len > max ? "\n" + prefix : " "));
|
|
1564
1623
|
}
|
|
1565
1624
|
log(`${prefix}Check out ${color.bold("README.md")} for development and deploy instructions.`);
|
|
1566
1625
|
await sleep(100);
|
|
1567
|
-
log(`\n${prefix}Join the community at ${color.cyan(`https://
|
|
1626
|
+
log(`\n${prefix}Join the community at ${color.cyan(`https://remix.run/discord`)}\n`);
|
|
1568
1627
|
await sleep(200);
|
|
1569
1628
|
}
|
|
1570
1629
|
const validPackageManagers = [
|
|
@@ -1572,14 +1631,37 @@ const validPackageManagers = [
|
|
|
1572
1631
|
"yarn",
|
|
1573
1632
|
"pnpm",
|
|
1574
1633
|
"bun",
|
|
1575
|
-
"deno"
|
|
1634
|
+
"deno",
|
|
1635
|
+
"nub"
|
|
1576
1636
|
];
|
|
1577
1637
|
function validatePackageManager(pkgManager) {
|
|
1578
1638
|
return validPackageManagers.find((name) => pkgManager === name) ?? "npm";
|
|
1579
1639
|
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Determine which package manager the user prefers.
|
|
1642
|
+
*
|
|
1643
|
+
* npm, pnpm, Yarn, Bun, Deno, and nub set the user agent environment variable
|
|
1644
|
+
* that can be used to determine which package manager ran the command.
|
|
1645
|
+
*/
|
|
1646
|
+
function detectPackageManager() {
|
|
1647
|
+
let { npm_config_user_agent } = process.env;
|
|
1648
|
+
if (!npm_config_user_agent) return void 0;
|
|
1649
|
+
try {
|
|
1650
|
+
let pkgManager = npm_config_user_agent.split("/")[0];
|
|
1651
|
+
if (pkgManager === "npm") return "npm";
|
|
1652
|
+
if (pkgManager === "pnpm") return "pnpm";
|
|
1653
|
+
if (pkgManager === "yarn") return "yarn";
|
|
1654
|
+
if (pkgManager === "bun") return "bun";
|
|
1655
|
+
if (pkgManager === "deno") return "deno";
|
|
1656
|
+
if (pkgManager === "nub") return "nub";
|
|
1657
|
+
return;
|
|
1658
|
+
} catch {
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1580
1662
|
async function installDependencies({ pkgManager, cwd, showInstallOutput }) {
|
|
1581
1663
|
try {
|
|
1582
|
-
await
|
|
1664
|
+
await runCommand(pkgManager, ["install"], {
|
|
1583
1665
|
cwd,
|
|
1584
1666
|
stdio: showInstallOutput ? "inherit" : "ignore"
|
|
1585
1667
|
});
|
|
@@ -1588,6 +1670,16 @@ async function installDependencies({ pkgManager, cwd, showInstallOutput }) {
|
|
|
1588
1670
|
throw err;
|
|
1589
1671
|
}
|
|
1590
1672
|
}
|
|
1673
|
+
function runCommand(command, args, options) {
|
|
1674
|
+
return new Promise((resolve, reject) => {
|
|
1675
|
+
let child = spawn(command, args, options);
|
|
1676
|
+
child.on("error", reject);
|
|
1677
|
+
child.on("exit", (code, signal) => {
|
|
1678
|
+
if (code === 0) resolve();
|
|
1679
|
+
else reject(/* @__PURE__ */ new Error(signal ? `${command} exited with signal ${signal}` : `${command} exited with code ${code}`));
|
|
1680
|
+
});
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1591
1683
|
async function updatePackageJSON(ctx) {
|
|
1592
1684
|
let packageJSONPath = path.join(ctx.cwd, "package.json");
|
|
1593
1685
|
if (!existsSync(packageJSONPath)) {
|
|
@@ -1652,6 +1744,7 @@ ${color.arg("--template <name>")} ${color.dim(`The project template to use`)}
|
|
|
1652
1744
|
${color.arg("--[no-]install")} ${color.dim(`Whether or not to install dependencies after creation`)}
|
|
1653
1745
|
${color.arg("--package-manager")} ${color.dim(`The package manager to use`)}
|
|
1654
1746
|
${color.arg("--show-install-output")} ${color.dim(`Whether to show the output of the install process`)}
|
|
1747
|
+
${color.arg("--[no-]agent-skills")} ${color.dim(`Whether or not to include the React Router agent skill`)}
|
|
1655
1748
|
${color.arg("--[no-]git-init")} ${color.dim(`Whether or not to initialize a Git repository`)}
|
|
1656
1749
|
${color.arg("--yes, -y")} ${color.dim(`Skip all option prompts and run setup`)}
|
|
1657
1750
|
${color.arg("--react-router-version, -v")} ${color.dim(`The version of React Router to use`)}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-react-router",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "8.0
|
|
4
|
+
"version": "8.2.0",
|
|
5
5
|
"description": "Create a new React Router app",
|
|
6
6
|
"homepage": "https://reactrouter.com",
|
|
7
7
|
"bugs": {
|
|
@@ -34,15 +34,12 @@
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"arg": "^5.0.1",
|
|
38
|
-
"execa": "9.6.1",
|
|
39
37
|
"gunzip-maybe": "^1.4.2",
|
|
40
38
|
"log-update": "^8.0.0",
|
|
41
39
|
"picocolors": "^1.1.1",
|
|
42
40
|
"semver": "^7.8.1",
|
|
43
41
|
"sisteransi": "^1.0.5",
|
|
44
42
|
"sort-package-json": "^3.6.1",
|
|
45
|
-
"strip-ansi": "^7.2.0",
|
|
46
43
|
"tar-fs": "^3.1.2"
|
|
47
44
|
},
|
|
48
45
|
"devDependencies": {
|