vite-plugin-react-router-routecraft 0.1.0 → 0.1.1
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 +5 -1
- package/README.md +5 -4
- package/dist/core/scanner.js +8 -8
- package/docs/architecture/index.md +1 -1
- package/docs/examples/complete-app.md +3 -3
- package/docs/guides/ai-assistants.md +61 -0
- package/docs/guides/configuration.md +1 -1
- package/docs/guides/routing-conventions.md +90 -150
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
本文件记录 Routecraft 的面向用户变更。
|
|
4
4
|
|
|
5
|
+
## 0.1.1
|
|
6
|
+
|
|
7
|
+
- 完善 AI 使用指南与 Skill 对已安装插件版本文档的定位说明,明确文档缺失或版本不匹配时的处理方式。
|
|
8
|
+
|
|
5
9
|
## 0.1.0
|
|
6
10
|
|
|
7
|
-
- 实现
|
|
11
|
+
- 实现 Routecraft 目录约定到 React Router Data Mode `RouteObject[]` 的编译。
|
|
8
12
|
- 支持多路由组与布局、动态段、末尾 splat、可选 loader/action、错误边界、HydrateFallback 和 middleware。
|
|
9
13
|
- 支持按模块逐属性选择 eager/lazy,生成 `typed-router.d.ts` 和类型化 `href` 辅助接口。
|
|
10
14
|
- 提供目录扫描诊断、Vite HMR、可选开发期 DevTools、中文使用指南和可构建示例。
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## 特性
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- 以目录表达路由层级,并通过 `page.tsx`、`layout.tsx` 等 Routecraft 约定文件生成路由对象;
|
|
12
12
|
- 路由组 `(group)`、私有目录 `_private`、`[param]` 动态段及末尾 `[...parts]` splat;
|
|
13
13
|
- 多分支、多布局;不同 route group 可各自拥有 layout;
|
|
14
14
|
- 组件、loader、action、错误边界与 hydration fallback 逐属性选择 eager/lazy;
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
- [灵机一动:项目起点与原始设计方案](docs/design/routecraft-design.md)
|
|
22
22
|
- [配置指南](docs/guides/configuration.md)
|
|
23
23
|
- [目录路由约定](docs/guides/routing-conventions.md)
|
|
24
|
+
- [AI 编码助手](docs/guides/ai-assistants.md)
|
|
24
25
|
- [DevTools 指南](docs/guides/devtools.md)
|
|
25
26
|
|
|
26
27
|
## 试用示例
|
|
@@ -92,10 +93,10 @@ npm run pack:check
|
|
|
92
93
|
## 已知边界
|
|
93
94
|
|
|
94
95
|
- `loading.tsx` 不会自动建立导航 loading UI;应用可用 React Router 的 `useNavigation()` 实现。
|
|
95
|
-
- `hydrate-fallback.tsx`
|
|
96
|
+
- `hydrate-fallback.tsx` 映射为 React Router 的 `HydrateFallback`,用于 hydration fallback;它不是应用内导航状态组件。
|
|
96
97
|
- 根 `middleware.ts` 位于共同合成路由根,影响所有分支。middleware 不是服务端安全边界。
|
|
97
|
-
- `[...parts]`
|
|
98
|
-
-
|
|
98
|
+
- `[...parts]` 映射为 React Router splat,参数通过 `params["*"]` 获取;`[[...parts]]` 不支持。
|
|
99
|
+
- 不提供服务端组件、服务端操作、HTTP 请求处理器、并行/拦截式路由、框架级 metadata 或 Framework Mode typegen。
|
|
99
100
|
- `useLoaderData()` 的业务返回值类型不做跨文件自动推导。
|
|
100
101
|
|
|
101
102
|
详见[目录规则与语义边界](docs/guides/routing-conventions.md)。
|
package/dist/core/scanner.js
CHANGED
|
@@ -50,11 +50,11 @@ function scanChildren(directory, rootPath, diagnostics) {
|
|
|
50
50
|
continue;
|
|
51
51
|
}
|
|
52
52
|
const childPath = join(directory, entry.name);
|
|
53
|
-
if (
|
|
53
|
+
if (isUnsupportedRouteDirectory(entry.name)) {
|
|
54
54
|
diagnostics.push({
|
|
55
|
-
code: "
|
|
55
|
+
code: "RC_UNSUPPORTED_ROUTE_CONVENTION",
|
|
56
56
|
level: "warning",
|
|
57
|
-
message: `目录“${entry.name}
|
|
57
|
+
message: `目录“${entry.name}”使用了 Routecraft 当前不支持的目录约定;该目录不会生成路由。`,
|
|
58
58
|
file: relative(rootPath, childPath).split("\\").join("/"),
|
|
59
59
|
});
|
|
60
60
|
continue;
|
|
@@ -89,7 +89,7 @@ function scanChildren(directory, rootPath, diagnostics) {
|
|
|
89
89
|
}
|
|
90
90
|
return children;
|
|
91
91
|
}
|
|
92
|
-
function
|
|
92
|
+
function isUnsupportedRouteDirectory(name) {
|
|
93
93
|
return name.startsWith("@") || /^\(\.{1,3}\)/u.test(name);
|
|
94
94
|
}
|
|
95
95
|
function scanFiles(directory, rootPath, diagnostics) {
|
|
@@ -105,9 +105,9 @@ function scanFiles(directory, rootPath, diagnostics) {
|
|
|
105
105
|
const baseName = entry.name.replace(/\.[^.]+$/u, "");
|
|
106
106
|
if (unsupportedConventions.has(baseName)) {
|
|
107
107
|
diagnostics.push({
|
|
108
|
-
code: "
|
|
108
|
+
code: "RC_UNSUPPORTED_ROUTE_CONVENTION",
|
|
109
109
|
level: "warning",
|
|
110
|
-
message: `“${entry.name}
|
|
110
|
+
message: `“${entry.name}”使用了 Routecraft 当前不支持的文件约定;该文件不会生成路由功能。`,
|
|
111
111
|
file: relative(rootPath, join(directory, entry.name)).split("\\").join("/"),
|
|
112
112
|
});
|
|
113
113
|
}
|
|
@@ -116,9 +116,9 @@ function scanFiles(directory, rootPath, diagnostics) {
|
|
|
116
116
|
const stem = entry.name.slice(0, -extension.length);
|
|
117
117
|
if (unsupportedConventions.has(stem)) {
|
|
118
118
|
diagnostics.push({
|
|
119
|
-
code: "
|
|
119
|
+
code: "RC_UNSUPPORTED_ROUTE_CONVENTION",
|
|
120
120
|
level: "warning",
|
|
121
|
-
message: `“${entry.name}
|
|
121
|
+
message: `“${entry.name}”使用了 Routecraft 当前不支持的文件约定;该文件不会生成路由功能。`,
|
|
122
122
|
file: relative(rootPath, join(directory, entry.name)).split("\\").join("/"),
|
|
123
123
|
});
|
|
124
124
|
continue;
|
|
@@ -76,7 +76,7 @@ Routecraft 为路由根产生共同的 pathless 根对象;`(auth)`、`(workspa
|
|
|
76
76
|
|
|
77
77
|
- 有 error 时插件不把有错误的 IR 编译成“成功”快照;生产构建报错并终止。
|
|
78
78
|
- 开发服务器将诊断写入 Vite 日志,DevTools 快照可呈现错误原因。
|
|
79
|
-
-
|
|
79
|
+
- 未注册的保留文件名和特殊目录按当前实现产生 warning,并跳过,不生成路由节点。
|
|
80
80
|
- 修复错误后重新扫描,重新生成路由和声明文件。
|
|
81
81
|
|
|
82
82
|
## 开发期变更和刷新
|
|
@@ -818,7 +818,7 @@ export default function HydrationFallback() {
|
|
|
818
818
|
}
|
|
819
819
|
```
|
|
820
820
|
|
|
821
|
-
该文件生成根结构路由的 `HydrateFallback
|
|
821
|
+
该文件生成根结构路由的 `HydrateFallback`,用于 hydration fallback;应用内导航提示应由应用根据 React Router 导航状态自行呈现。
|
|
822
822
|
|
|
823
823
|
`src/routes/not-found.tsx`:
|
|
824
824
|
|
|
@@ -836,7 +836,7 @@ export default function NotFoundPage() {
|
|
|
836
836
|
}
|
|
837
837
|
```
|
|
838
838
|
|
|
839
|
-
当前实现只接受**根目录** `not-found.tsx`,并将它生成 React Router `/*` catch-all
|
|
839
|
+
当前实现只接受**根目录** `not-found.tsx`,并将它生成 React Router `/*` catch-all 叶子。
|
|
840
840
|
|
|
841
841
|
## 10. 文件属性到 Route Object 对照
|
|
842
842
|
|
|
@@ -952,4 +952,4 @@ npm --prefix examples/complete-app run dev
|
|
|
952
952
|
- 登录 action 不建立 session、不验证账号;生产身份校验必须在服务端完成。
|
|
953
953
|
- 项目数组在前端内存中,刷新后重置;生产项目数据应经由经过授权的服务端 API 访问。
|
|
954
954
|
- Routecraft 当前生成 URL、参数和 Route ID 类型,不推断业务 loader/action 返回类型。
|
|
955
|
-
- Data Mode 的浏览器 loader/action
|
|
955
|
+
- Data Mode 的浏览器 loader/action 是路由应用代码,不是后端 HTTP endpoint;敏感操作应由服务端接口验证。
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# 使用 AI 编码助手
|
|
2
|
+
|
|
3
|
+
Routecraft 提供一个可安装的 Agent Skill,帮助 AI 编码助手在现有 Vite 项目中正确规划和维护 Routecraft 文件路由。Skill 是面向 AI 的操作指引,不会修改 Vite 插件运行时,也不会代替 React Router。
|
|
4
|
+
|
|
5
|
+
## 安装 `routecraft-file-routing`
|
|
6
|
+
|
|
7
|
+
先进入使用 Routecraft 的应用项目,再运行:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx skills add alon-wu/vite-plugin-react-router-routecraft --skill routecraft-file-routing
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
安装工具会引导选择可用的编码助手和安装方式。默认按项目安装,便于团队共享;安装完成后请检查它新增或更新的 Skill 文件、助手目录链接和 `skills-lock.json`,只提交你希望团队共享的项目级文件。若要安装到个人环境供多个项目使用,可以加 `--global`。也可指定目标助手,例如:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npx skills add alon-wu/vite-plugin-react-router-routecraft \
|
|
17
|
+
--skill routecraft-file-routing \
|
|
18
|
+
--agent codex
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`skills` 命令行工具及各 AI 助手的支持范围可能变化;请以安装时工具提供的选项为准。该命令从 GitHub 获取 Skill,不会安装或更新 `vite-plugin-react-router-routecraft` npm 依赖,也不会改写应用的 Vite 配置。
|
|
22
|
+
|
|
23
|
+
## 更新和移除
|
|
24
|
+
|
|
25
|
+
在应用项目目录中更新:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npx skills update routecraft-file-routing
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
移除项目级安装:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npx skills remove routecraft-file-routing
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
如果之前使用了全局安装,按工具提示选择全局范围或为对应目标助手移除。
|
|
38
|
+
|
|
39
|
+
## 使用示例
|
|
40
|
+
|
|
41
|
+
安装后,可以用自然语言请求 AI:
|
|
42
|
+
|
|
43
|
+
- “在当前 Routecraft 项目里,为工作区增加一个项目详情页,沿用已有布局,并使用动态项目 ID。”
|
|
44
|
+
- “检查这组页面的 loader 和 lazy 设置,只调整项目详情路由,不要改其他布局。”
|
|
45
|
+
- “根据当前 Routecraft 版本核对这个路由目录是否符合约定;遇到不支持的目录或文件约定时先解释,不要模拟实现。”
|
|
46
|
+
|
|
47
|
+
Skill 会要求助手先检查项目中 Routecraft 的实际版本、Vite 配置、路由目录和现有入口。插件完整指南随 npm 包发布,通常可在应用项目的 `node_modules/vite-plugin-react-router-routecraft/docs/guides/` 中查阅;若包管理器未提供这一直接路径,助手应先解析实际安装位置,而不是假设用户本地存在插件源码仓库。若完整指南不可用,Skill 会要求助手说明资料缺口,不把文档站最新版误称为安装版本文档。它不会替用户安装插件、覆盖现有路由架构或假设所有 React Router 项目都使用 Routecraft。
|
|
48
|
+
|
|
49
|
+
## 不使用 Skill CLI 时
|
|
50
|
+
|
|
51
|
+
可以从仓库的 `skills/routecraft-file-routing/` 目录手动安装 `SKILL.md` 及整个目录到所用 AI 助手支持的项目级或个人级 Skills 目录。各产品的目录和刷新方式不同,请查看相应助手的当前文档。
|
|
52
|
+
|
|
53
|
+
## 相关资料
|
|
54
|
+
|
|
55
|
+
- [安装与快速开始](/getting-started)
|
|
56
|
+
- [目录与文件约定](/guides/routing-conventions)
|
|
57
|
+
- [Lazy、loader 与 action](/guides/lazy-and-data)
|
|
58
|
+
- [配置参考](/guides/configuration)
|
|
59
|
+
- [类型声明与 `href()`](/guides/type-generation)
|
|
60
|
+
- [Agent Skills 格式规范](https://agentskills.io/specification)
|
|
61
|
+
- [Skills CLI 命令参考](https://github.com/vercel-labs/skills/blob/main/docs/commands.md)
|
|
@@ -61,7 +61,7 @@ Routecraft 本身设置 `enforce: "pre"`。应用仍需按 Vite/React 的正常
|
|
|
61
61
|
|
|
62
62
|
- 路由根目录不存在、特殊文件导出缺失、配置语法无效或公开 URL 冲突:生成错误诊断;生产构建失败,不输出有效外观的部分路由表。
|
|
63
63
|
- `route.config.ts` 只读取静态对象字面量,不执行配置模块。
|
|
64
|
-
-
|
|
64
|
+
- `loading.tsx`、`template.tsx`、`route.tsx`、`default.tsx` 等未实现的约定名称会产生警告并被跳过,不会自动转换为其他功能。
|
|
65
65
|
- 支持项和“不支持”边界以[目录规则表](/guides/routing-conventions#routecraft-当前实现规则)为准。
|
|
66
66
|
|
|
67
67
|
## 当前 peer 范围
|
|
@@ -1,191 +1,131 @@
|
|
|
1
1
|
# 目录与文件约定
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Routecraft 扫描 Vite 项目中配置的路由根目录,将约定文件编译为 React Router Data Mode 的路由对象树。本文说明 Routecraft 实际识别的目录、文件、校验规则及生成结果;未列出的文件不会被当作路由约定处理。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 路由根目录与扫描范围
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `routesDir` 是路由文件扫描根目录,默认值为 `src/routes`,可在 Vite 插件配置中改为其他相对或绝对路径。
|
|
8
|
+
- 根目录自身代表共同路由根;它的约定文件作用于所有路由分支。
|
|
9
|
+
- 普通子目录按路径层级递归扫描。以下划线 `_` 或点 `.` 开头的目录及其全部后代会被跳过。
|
|
10
|
+
- 未包含 Routecraft 约定文件、也没有包含有效路由后代的普通目录不会生成路由节点。
|
|
11
|
+
- 扫描仅识别下表所列的 `.ts` / `.tsx` 文件;数据模块、中间件和目录配置只接受 `.ts`。
|
|
12
|
+
- 扫描结果按目录名排序,以确保生成结果稳定。`.d.ts` 文件(包括自动生成的 `typed-router.d.ts`)会被忽略。
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
app/
|
|
11
|
-
├── layout.tsx # 根布局:Next 文档壳、html/body 等
|
|
12
|
-
├── page.tsx # /
|
|
13
|
-
├── dashboard/
|
|
14
|
-
│ ├── layout.tsx # /dashboard 子树共享布局
|
|
15
|
-
│ ├── page.tsx # /dashboard
|
|
16
|
-
│ └── projects/
|
|
17
|
-
│ └── [projectId]/
|
|
18
|
-
│ └── page.tsx # /dashboard/projects/:projectId
|
|
19
|
-
└── (marketing)/
|
|
20
|
-
└── about/
|
|
21
|
-
└── page.tsx # /about;组名不出现在 URL
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### 1.1 页面、布局与嵌套
|
|
25
|
-
|
|
26
|
-
- **目录段**组织 URL 层级;目录名本身不是充分的页面声明。
|
|
27
|
-
- **`page.tsx`** 使所在路由段有页面入口。
|
|
28
|
-
- **`layout.tsx`** 按目录嵌套包围页面及后代;Next.js 根布局还有 HTML 文档职责,普通布局可保留跨导航状态。
|
|
29
|
-
- **`template.tsx`** 与 layout 的重新挂载语义不同。
|
|
30
|
-
- **`loading.tsx`**、**`error.tsx`** 和 **`not-found.tsx`** 在 Next.js 中是框架识别的边界文件,不只是普通 React 组件。
|
|
31
|
-
|
|
32
|
-
### 1.2 路由组、私有目录和 URL 段
|
|
14
|
+
## 目录段规则
|
|
33
15
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
16
|
+
| 目录名 | Routecraft 解释 | 生成的路径 |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| `workspace/` | 静态路径段 | `workspace` |
|
|
19
|
+
| `[projectId]/` | 动态路径段;参数名须为合法 TypeScript 标识符 | `:projectId` |
|
|
20
|
+
| `[...parts]/` | 末尾通配路径段;参数名须为合法 TypeScript 标识符 | `*` |
|
|
21
|
+
| `(account)/` | 无 URL 路径的结构分组;名称仅用于组织目录 | 不生成 `path` |
|
|
22
|
+
| `_private/`、`.hidden/` | 私有或隐藏实现目录;整个子树跳过 | 不生成路由 |
|
|
39
23
|
|
|
40
|
-
###
|
|
24
|
+
### 静态段
|
|
41
25
|
|
|
42
|
-
|
|
26
|
+
静态目录名只允许 ASCII 字母、数字、下划线和连字符,即 `A-Z`、`a-z`、`0-9`、`_`、`-`。例如 `sign-in`、`workspace_v2` 合法;空格、点号和其他字符不符合当前校验规则。
|
|
43
27
|
|
|
44
|
-
|
|
28
|
+
### 动态段
|
|
45
29
|
|
|
46
|
-
|
|
30
|
+
以一对方括号包裹参数名,例如 `[projectId]`。参数名遵循 TypeScript 标识符格式。Routecraft 将其转换为 React Router 动态段;实际匹配参数由 React Router 提供给路由组件和数据函数。
|
|
47
31
|
|
|
48
|
-
###
|
|
32
|
+
### 通配段
|
|
49
33
|
|
|
50
|
-
|
|
51
|
-
| --- | --- |
|
|
52
|
-
| URL 段按目录嵌套 | 普通目录段拼接成 React Router `path`。 |
|
|
53
|
-
| `page` 表示页面入口 | `page.tsx`/`page.ts` 生成 React Router index route,页面组件为默认导出。 |
|
|
54
|
-
| 目录布局 | `layout.tsx`/`layout.ts` 附着在对应目录结构路由的 `Component`;布局组件必须渲染 `<Outlet />`。 |
|
|
55
|
-
| 无 URL 的路由分组 | `(group)` 编译为无 `path` 的 pathless 父路由;组名保留在 ID/来源信息,但不进入 URL。 |
|
|
56
|
-
| 私有实现子树 | `_private` 开头的子目录整棵跳过;点开头目录也跳过。 |
|
|
57
|
-
| 方括号动态段 | `[projectId]` 编译为 `:projectId`。 |
|
|
58
|
-
| 错误边界/fallback 模块 | `error.tsx` 映射 `ErrorBoundary`;`hydrate-fallback.tsx` 映射 `HydrateFallback`。 |
|
|
59
|
-
| 路由数据模块 | 可选 `loader.ts`、`action.ts` 映射对应路由对象属性,实际函数契约由 React Router 规定。 |
|
|
34
|
+
`[...parts]` 将生成 React Router 的 `*` 路径段,读取值时使用 `params["*"]`。该目录必须是路由路径的最后一段,不能包含有效路由后代。`[[...parts]]` 不属于支持的目录语法。
|
|
60
35
|
|
|
61
|
-
###
|
|
36
|
+
### 结构分组
|
|
62
37
|
|
|
63
|
-
|
|
64
|
-
| --- | --- |
|
|
65
|
-
| 根布局输出 `<html>`/`<body>` | 不实现;文档壳仍由 Vite `index.html` 和 React 挂载入口负责。 |
|
|
66
|
-
| `loading.tsx` | 不支持;不推断自动 Suspense/loading UI。应用可使用 React Router 导航状态 API 自行呈现导航提示。 |
|
|
67
|
-
| `template.tsx` | 不支持。 |
|
|
68
|
-
| `route.ts` Route Handler | 不支持;Routecraft 不提供服务端 HTTP 处理器。 |
|
|
69
|
-
| Parallel/Intercepting Routes(`@slot`、`(.)` 等) | 不模拟多槽渲染或拦截路由;当前实现会跳过相关目录并产生警告。 |
|
|
70
|
-
| Server Components/Server Actions | 不支持;不是 Vite + React Router Data Mode 的等价路由字段。 |
|
|
71
|
-
| Next metadata、静态参数生成等 | 不支持;不生成 metadata 或 Next 构建工作流。 |
|
|
72
|
-
| Optional catch-all `[[...parts]]` | 不支持。 |
|
|
38
|
+
`(account)` 这样的目录会生成一个不含 `path` 的父路由节点。组名不出现在 URL 中,但节点可保留父子关系、目录级布局和中间件作用范围。不同分组若生成相同的可访问 URL,仍会发生路由冲突;分组名不会使 URL 唯一。
|
|
73
39
|
|
|
74
|
-
|
|
40
|
+
### 私有和隐藏目录
|
|
75
41
|
|
|
76
|
-
|
|
42
|
+
以下划线或点开头的目录会连同其后代一起排除在扫描之外。可用它们存放不会参与路由生成的实现文件。
|
|
77
43
|
|
|
78
|
-
|
|
79
|
-
| --- | --- | --- | --- |
|
|
80
|
-
| 路由根目录 | `routesDir` | 必须已存在且是目录。 | 所有扫描结果合入共同根路由对象。 |
|
|
81
|
-
| 页面 | `page.tsx` 或 `page.ts` | 必须有默认导出。 | 同目录结构路由的 `children` 中新增 `{ index: true, ... }`。 |
|
|
82
|
-
| 布局 | `layout.tsx` 或 `layout.ts` | 必须有默认导出;应渲染 `<Outlet />`。 | 当前目录结构路由的 `Component`。 |
|
|
83
|
-
| route group | `(name)/` | 名称仅允许 ASCII 字母、数字、`_`、`-`。 | `{ id, children }` 无 `path`;保留父子与布局边界。 |
|
|
84
|
-
| 私有目录 | `_name/` | 整棵子树不扫描。 | 不生成节点。 |
|
|
85
|
-
| 隐藏目录 | `.name/` | 整棵子树不扫描。 | 不生成节点。 |
|
|
86
|
-
| 静态段 | `workspace/`、`sign-in/` | 仅 ASCII 字母、数字、`_`、`-`。 | `{ path: "workspace", children: [...] }`。 |
|
|
87
|
-
| 动态段 | `[projectId]/` | 参数名须是合法 TS 标识符。 | `{ path: ":projectId", children: [...] }`;React Router 将其放入匹配参数。 |
|
|
88
|
-
| splat 段 | `[...parts]/` | 参数名须合法;必须是路由路径末尾,不能有后代段。 | `{ path: "*", children: [...] }`;匹配值按 React Router 的 `params["*"]` 字符串读取。 |
|
|
89
|
-
| 错误边界 | `error.tsx`/`.ts` | 默认导出组件。 | 当前结构路由 `ErrorBoundary`。 |
|
|
90
|
-
| Hydration fallback | `hydrate-fallback.tsx`/`.ts` | 默认导出组件。 | 当前结构路由 `HydrateFallback`。不是导航 loading 状态组件。 |
|
|
91
|
-
| 404 页面 | 仅路由根 `not-found.tsx`/`.ts` | 默认导出组件;放在非根目录是错误。 | 根共同路由的 `*` catch-all 叶子;不是 Next `not-found` 冒泡模型。 |
|
|
92
|
-
| 页面 loader/action | 同目录 `loader.ts`、`action.ts` | 分别需命名导出 `loader`/`action`;同目录必须有 `page`。 | 页面 index route 对应的属性。缺文件就省略该属性。 |
|
|
93
|
-
| 布局 loader/action | 同目录 `layout.loader.ts`、`layout.action.ts` | 需要同目录 layout;分别命名导出 `loader`/`action`。 | 目录结构路由对应的属性。 |
|
|
94
|
-
| middleware | `middleware.ts` | 必须命名导出 `middleware`;静态导入。 | 当前结构路由的 `middleware: [middleware]`;根文件放共同根。 |
|
|
95
|
-
| 加载配置 | `route.config.ts` | 与 `page`、`layout`、`error`、`hydrate-fallback` 或根 `not-found` 共置。只能用允许的静态配置对象。 | 影响本目录模块的独立 eager/lazy 决策,不生成 route 属性。 |
|
|
96
|
-
| 普通 colocated 文件 | 其他名称,如 `components.tsx`、`styles.css` | 不属于特殊文件约定。 | 不单独生成路由。 |
|
|
44
|
+
## 约定文件与路由对象映射
|
|
97
45
|
|
|
98
|
-
|
|
46
|
+
Routecraft 会将同一目录内的文件按职责放到对应的路由节点上。页面是当前路径的索引子路由;布局、边界组件和中间件附着在目录对应的结构路由上。
|
|
99
47
|
|
|
100
|
-
|
|
48
|
+
| 文件 | 导出要求 | 对应结果 |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `page.tsx` / `page.ts` | 默认导出页面组件 | 在当前目录路径下生成 `{ index: true, ... }` 子路由,并将组件映射到 `Component` 或 `lazy`。 |
|
|
51
|
+
| `layout.tsx` / `layout.ts` | 默认导出布局组件 | 映射为当前目录结构路由的 `Component` 或 `lazy`。布局需要渲染 `<Outlet />` 才能呈现子路由。 |
|
|
52
|
+
| `error.tsx` / `error.ts` | 默认导出错误边界组件 | 映射为当前结构路由的 `ErrorBoundary` 或 `lazy`。 |
|
|
53
|
+
| `hydrate-fallback.tsx` / `hydrate-fallback.ts` | 默认导出组件 | 映射为当前结构路由的 `HydrateFallback` 或 `lazy`,用于 hydration fallback。 |
|
|
54
|
+
| 根目录 `not-found.tsx` / `not-found.ts` | 默认导出组件;仅允许置于路由根 | 在共同路由根下生成 `path: "*"` 的通配叶子路由。 |
|
|
55
|
+
| `loader.ts` | 命名导出 `loader`;需同目录页面 | 映射为页面索引路由的 `loader`。 |
|
|
56
|
+
| `action.ts` | 命名导出 `action`;需同目录页面 | 映射为页面索引路由的 `action`。 |
|
|
57
|
+
| `layout.loader.ts` | 命名导出 `loader`;需同目录布局 | 映射为目录结构路由的 `loader`。 |
|
|
58
|
+
| `layout.action.ts` | 命名导出 `action`;需同目录布局 | 映射为目录结构路由的 `action`。 |
|
|
59
|
+
| `middleware.ts` | 命名导出 `middleware` | 映射为当前结构路由的 `middleware` 数组,始终静态导入。 |
|
|
60
|
+
| `route.config.ts` | 默认导出静态配置对象 | 调整当前目录受支持模块属性的 eager/lazy 方式;本身不生成路由属性。 |
|
|
101
61
|
|
|
102
|
-
|
|
103
|
-
- 动态段 `[id]` 内是 TS 标识符;动态参数重复名称会产生诊断。
|
|
104
|
-
- 动态段名称不用于区分 URL 冲突:`[projectId]` 和 `[slug]` 在相同位置属于同一 URL 形状。
|
|
105
|
-
- `(public)/about/page.tsx` 与 `about/page.tsx` 等若产生相同的可访问 URL,会发生冲突;组名不能防止冲突。
|
|
106
|
-
- `[...parts]` 有后代目录时会失败;可选 catch-all `[[...parts]]` 不支持。
|
|
107
|
-
- 根 `page.tsx` 生成 `/` index 页面;其他页面都生成其父路径的 index route。
|
|
108
|
-
- 文件夹只有普通文件、没有路由约定文件且没有路由后代时,不生成节点。
|
|
62
|
+
若约定组件文件或数据模块缺少必需导出、数据模块没有对应页面/布局、配置文件放置位置错误,Routecraft 会输出错误诊断。约定文件不能在同一目录重复出现 `.ts` 和 `.tsx` 两种版本。
|
|
109
63
|
|
|
110
|
-
###
|
|
64
|
+
### 页面、布局与多分支
|
|
111
65
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
## 4. 从目录到 React Router 对象:逐级映射
|
|
115
|
-
|
|
116
|
-
React Router Data Mode 接收 `createBrowserRouter(routes)` 的 Route Object 树;path/index/children 表达匹配与嵌套,布局组件通过 `<Outlet />` 呈现子节点。索引路由是无 path 的 `{ index: true }` 子路由。见 React Router 官方[路由配置](https://reactrouter.com/start/data/routing)。
|
|
117
|
-
|
|
118
|
-
例如:
|
|
66
|
+
页面始终编译为其目录路径下的索引子路由。因此一个路径段可以同时拥有 `layout`、`page` 和更深层的路由后代。例如:
|
|
119
67
|
|
|
120
68
|
```text
|
|
121
69
|
src/routes/
|
|
122
70
|
├── (auth)/
|
|
123
71
|
│ └── auth/
|
|
124
72
|
│ ├── layout.tsx
|
|
125
|
-
│
|
|
126
|
-
│
|
|
127
|
-
│
|
|
128
|
-
│ └──
|
|
73
|
+
│ ├── sign-in/
|
|
74
|
+
│ │ └── page.tsx
|
|
75
|
+
│ └── sign-up/
|
|
76
|
+
│ └── page.tsx
|
|
129
77
|
└── (workspace)/
|
|
130
78
|
└── workspace/
|
|
131
79
|
├── layout.tsx
|
|
80
|
+
├── page.tsx
|
|
132
81
|
└── projects/
|
|
133
82
|
└── [projectId]/
|
|
134
83
|
└── page.tsx
|
|
135
84
|
```
|
|
136
85
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
path: "
|
|
150
|
-
|
|
151
|
-
{
|
|
152
|
-
index: true,
|
|
153
|
-
loader: signInLoader,
|
|
154
|
-
lazy: { Component: /* 页面组件导入 */ },
|
|
155
|
-
},
|
|
156
|
-
],
|
|
157
|
-
},
|
|
158
|
-
],
|
|
159
|
-
},
|
|
160
|
-
],
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
// 第二个 route group 不与认证分支共用布局
|
|
164
|
-
children: [
|
|
165
|
-
{
|
|
166
|
-
path: "workspace",
|
|
167
|
-
Component: WorkspaceLayout,
|
|
168
|
-
children: [
|
|
169
|
-
{
|
|
170
|
-
path: "projects",
|
|
171
|
-
children: [
|
|
172
|
-
{
|
|
173
|
-
path: ":projectId",
|
|
174
|
-
children: [{ index: true, lazy: { Component: /* 页面组件导入 */ } }],
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
},
|
|
178
|
-
],
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
},
|
|
182
|
-
]
|
|
86
|
+
上例形成两个共享共同路由根的分支:认证分支由 `auth/layout.tsx` 包裹,工作区分支由 `workspace/layout.tsx` 包裹;各分支仍由应用创建的同一个 React Router 实例管理。`(auth)` 和 `(workspace)` 仅用于组织结构,不进入公开 URL。示意映射如下:
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
共同路由根
|
|
90
|
+
├── pathless group
|
|
91
|
+
│ └── path: "auth" Component: AuthLayout
|
|
92
|
+
│ ├── path: "sign-in" └── index: true, Component: SignIn
|
|
93
|
+
│ └── path: "sign-up" └── index: true, Component: SignUp
|
|
94
|
+
└── pathless group
|
|
95
|
+
└── path: "workspace" Component: WorkspaceLayout
|
|
96
|
+
├── index: true, Component: WorkspaceHome
|
|
97
|
+
└── path: "projects"
|
|
98
|
+
└── path: ":projectId"
|
|
99
|
+
└── index: true, Component: ProjectDetails
|
|
183
100
|
```
|
|
184
101
|
|
|
185
|
-
|
|
102
|
+
对应的 URL 分别为 `/auth/sign-in`、`/auth/sign-up`、`/workspace` 和 `/workspace/projects/:projectId`。此图省略自动生成的 `id`、模块导入和数据属性;完整对象形状取决于每个模块的 lazy 配置。
|
|
103
|
+
|
|
104
|
+
## 可选数据模块与逐属性懒加载
|
|
105
|
+
|
|
106
|
+
`loader.ts`、`action.ts`、`layout.loader.ts` 和 `layout.action.ts` 都是可选的。文件不存在时,生成对象中不会出现对应属性,也不会创建空函数或占位导入。页面组件、布局、数据函数、错误边界和 hydration fallback 可分别选择 eager 或 lazy。
|
|
107
|
+
|
|
108
|
+
- 插件选项 `defaultLazy`(默认 `true`)为未被目录配置覆盖的模块属性提供默认值。
|
|
109
|
+
- 同目录 `route.config.ts` 的 `lazy` 对象可用 `true` / `false` 分别覆盖 `layout`、`layoutLoader`、`layoutAction`、`page`、`loader`、`action`、`error`、`hydrateFallback`。
|
|
110
|
+
- 目录配置只影响该目录中实际存在的相应文件;不存在的模块不会产生属性。
|
|
111
|
+
- `middleware.ts` 始终静态导入,不接受 lazy 配置。
|
|
112
|
+
- 路由匹配需要的 `id`、`path`、`index` 和 `children` 保持在路由对象静态部分。
|
|
113
|
+
|
|
114
|
+
配置只允许默认导出静态对象字面量,`lazy` 的每项必须是直接的布尔字面量;只允许 `import type`,不执行配置文件。完整例子和字段行为见 [Lazy、loader 与 action](/guides/lazy-and-data)。
|
|
115
|
+
|
|
116
|
+
## 冲突与错误规则
|
|
117
|
+
|
|
118
|
+
- 同一 URL 形状只能对应一条可访问路由。`users/[id]` 与 `users/[slug]` 会被视为相同路径形状并产生错误;动态参数名不同不构成区分。
|
|
119
|
+
- 路由组不进入 URL,因此不同组下相同的 URL 也会冲突。
|
|
120
|
+
- 同一路径中不能重复使用同一个动态参数名。
|
|
121
|
+
- 通配段必须处于路径末尾。
|
|
122
|
+
- `not-found` 约定文件仅允许放在路由根。
|
|
123
|
+
- 不识别的普通文件不会创建路由。`loading`、`template`、`route`、`default` 等保留名称的文件,以及 `@` 或以 `(.)`、`(..)`、`(...)` 开头的目录,会作为不支持的约定跳过并产生警告;不会被转换成其他功能。
|
|
124
|
+
|
|
125
|
+
有错误诊断时,插件不会将存在错误的部分结果伪装为有效路由表;请先处理 DevTools 或构建输出中的诊断。
|
|
186
126
|
|
|
187
|
-
##
|
|
127
|
+
## 生成结果由谁负责
|
|
188
128
|
|
|
189
|
-
Routecraft
|
|
129
|
+
Routecraft 负责扫描、校验并生成 React Router Data Mode 可消费的路由对象;URL 匹配、数据函数调用、中间件调度和 UI 渲染由 React Router 执行。`loader`/`action` 的业务返回值不会被跨文件推导为组件专属类型;Data Mode 中的业务代码也不因此获得服务端安全边界。
|
|
190
130
|
|
|
191
|
-
|
|
131
|
+
查看 [完整项目示例](/examples/complete-app) 了解一组端到端目录和业务代码;查看[架构设计](/architecture/)了解扫描器、路由中间表示与生成器的实现关系。
|