@modern-js/main-doc 2.58.3 → 2.60.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. package/docs/en/_meta.json +10 -5
  2. package/docs/en/apis/app/hooks/api/lambda.mdx +4 -48
  3. package/docs/en/apis/app/hooks/api/middleware.mdx +11 -0
  4. package/docs/en/apis/app/runtime/core/use-loader.mdx +1 -1
  5. package/docs/en/community/blog/v2-release-note.mdx +1 -1
  6. package/docs/en/components/enable-bff.mdx +19 -2
  7. package/docs/en/components/extend-bff-function.mdx +5 -0
  8. package/docs/en/components/init-app.mdx +0 -1
  9. package/docs/en/components/init-rspack-app.mdx +0 -1
  10. package/docs/en/components/other-plugins.mdx +0 -0
  11. package/docs/en/components/ssr-monitor.mdx +3 -0
  12. package/docs/en/configure/app/auto-load-plugin.mdx +4 -0
  13. package/docs/en/configure/app/output/ssg.mdx +52 -141
  14. package/docs/en/configure/app/plugins.mdx +2 -2
  15. package/docs/en/configure/app/tools/esbuild.mdx +1 -1
  16. package/docs/en/configure/app/tools/swc.mdx +1 -1
  17. package/docs/en/configure/app/tools/tailwindcss.mdx +1 -1
  18. package/docs/en/guides/_meta.json +0 -5
  19. package/docs/en/guides/advanced-features/_meta.json +3 -8
  20. package/docs/en/guides/advanced-features/bff/_meta.json +1 -1
  21. package/docs/en/guides/advanced-features/bff/extend-server.mdx +154 -0
  22. package/docs/en/guides/advanced-features/bff/frameworks.mdx +52 -123
  23. package/docs/en/guides/advanced-features/bff/function.mdx +108 -80
  24. package/docs/en/guides/advanced-features/bff/sdk.mdx +40 -51
  25. package/docs/en/guides/advanced-features/build-performance.mdx +6 -21
  26. package/docs/en/guides/advanced-features/page-performance/_meta.json +1 -0
  27. package/docs/en/guides/advanced-features/rspack-start.mdx +6 -14
  28. package/docs/en/guides/basic-features/_meta.json +31 -9
  29. package/docs/en/guides/basic-features/css/_meta.json +1 -0
  30. package/docs/en/guides/basic-features/css/css-in-js.mdx +34 -0
  31. package/docs/en/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -4
  32. package/docs/en/guides/basic-features/css/css.mdx +25 -0
  33. package/docs/en/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +5 -66
  34. package/docs/en/guides/basic-features/data/data-fetch.mdx +134 -235
  35. package/docs/en/guides/basic-features/data/data-write.mdx +66 -77
  36. package/docs/en/guides/basic-features/debug/_meta.json +1 -0
  37. package/docs/en/guides/basic-features/debug/rsdoctor.mdx +57 -0
  38. package/docs/en/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +2 -0
  39. package/docs/en/guides/basic-features/render/_meta.json +1 -0
  40. package/docs/en/guides/basic-features/render/ssg.mdx +208 -0
  41. package/docs/en/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +38 -50
  42. package/docs/en/guides/basic-features/render/ssr.mdx +301 -0
  43. package/docs/en/guides/basic-features/render/streaming-ssr.mdx +230 -0
  44. package/docs/en/guides/basic-features/routes.mdx +274 -263
  45. package/docs/en/guides/basic-features/static-assets/_meta.json +1 -0
  46. package/docs/en/guides/basic-features/static-assets.mdx +2 -2
  47. package/docs/en/guides/basic-features/testing/_meta.json +1 -0
  48. package/docs/en/guides/basic-features/testing/cypress.mdx +95 -0
  49. package/docs/en/guides/basic-features/testing/jest.mdx +148 -0
  50. package/docs/en/guides/basic-features/testing/playwright.mdx +111 -0
  51. package/docs/en/guides/basic-features/testing/vitest.mdx +100 -0
  52. package/docs/en/guides/concept/entries.mdx +9 -2
  53. package/docs/en/guides/deprecated.md +2 -0
  54. package/docs/en/guides/get-started/quick-start.mdx +1 -1
  55. package/docs/en/guides/get-started/tech-stack.mdx +4 -4
  56. package/docs/en/guides/topic-detail/_meta.json +0 -6
  57. package/docs/en/guides/topic-detail/generator/create/config.mdx +0 -10
  58. package/docs/en/guides/topic-detail/generator/create/use.mdx +0 -1
  59. package/docs/en/plugin/_meta.json +19 -0
  60. package/docs/en/plugin/cli-plugins/_meta.json +1 -0
  61. package/docs/en/plugin/cli-plugins/plugin-bff.mdx +5 -0
  62. package/docs/en/plugin/cli-plugins/plugin-ssg.mdx +5 -0
  63. package/docs/en/{guides/rsbuild-plugins → plugin/cli-plugins}/plugin-swc.mdx +7 -0
  64. package/docs/en/plugin/cli-plugins/plugin-tailwind.mdx +5 -0
  65. package/docs/en/plugin/cli-plugins.mdx +6 -0
  66. package/docs/en/{guides/advanced-features/rsbuild-plugin.mdx → plugin/introduction.mdx} +36 -11
  67. package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/extend.mdx +1 -1
  68. package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/implement.mdx +3 -3
  69. package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/plugin-api.mdx +2 -2
  70. package/docs/en/plugin/rsbuild-plugins/_meta.json +1 -0
  71. package/docs/en/plugin/rsbuild-plugins.mdx +3 -0
  72. package/docs/en/tutorials/first-app/c03-css.mdx +1 -1
  73. package/docs/zh/_meta.json +10 -5
  74. package/docs/zh/apis/app/hooks/api/lambda.mdx +5 -48
  75. package/docs/zh/apis/app/hooks/api/middleware.mdx +11 -0
  76. package/docs/zh/apis/app/runtime/core/use-loader.mdx +1 -1
  77. package/docs/zh/community/blog/v2-release-note.mdx +1 -1
  78. package/docs/zh/components/enable-bff.mdx +19 -2
  79. package/docs/zh/components/extend-bff-function.mdx +5 -0
  80. package/docs/zh/components/init-app.mdx +0 -1
  81. package/docs/zh/components/init-rspack-app.mdx +0 -1
  82. package/docs/zh/components/other-plugins.mdx +0 -0
  83. package/docs/zh/components/ssr-monitor.mdx +3 -0
  84. package/docs/zh/configure/app/auto-load-plugin.mdx +4 -0
  85. package/docs/zh/configure/app/output/ssg.mdx +49 -139
  86. package/docs/zh/configure/app/plugins.mdx +2 -2
  87. package/docs/zh/configure/app/tools/esbuild.mdx +1 -1
  88. package/docs/zh/configure/app/tools/swc.mdx +1 -1
  89. package/docs/zh/configure/app/tools/tailwindcss.mdx +1 -1
  90. package/docs/zh/guides/_meta.json +0 -5
  91. package/docs/zh/guides/advanced-features/_meta.json +3 -8
  92. package/docs/zh/guides/advanced-features/bff/_meta.json +1 -1
  93. package/docs/zh/guides/advanced-features/bff/extend-server.mdx +156 -0
  94. package/docs/zh/guides/advanced-features/bff/frameworks.mdx +51 -117
  95. package/docs/zh/guides/advanced-features/bff/function.mdx +69 -59
  96. package/docs/zh/guides/advanced-features/bff/sdk.mdx +27 -36
  97. package/docs/zh/guides/advanced-features/build-performance.mdx +6 -21
  98. package/docs/zh/guides/advanced-features/page-performance/_meta.json +1 -0
  99. package/docs/zh/guides/advanced-features/rspack-start.mdx +8 -17
  100. package/docs/zh/guides/basic-features/_meta.json +31 -9
  101. package/docs/zh/guides/basic-features/alias.mdx +5 -11
  102. package/docs/zh/guides/basic-features/css/_meta.json +1 -0
  103. package/docs/zh/guides/basic-features/css/css-in-js.mdx +34 -0
  104. package/docs/zh/guides/basic-features/css/css.mdx +25 -0
  105. package/docs/zh/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +3 -64
  106. package/docs/zh/guides/basic-features/data/data-fetch.mdx +96 -211
  107. package/docs/zh/guides/basic-features/data/data-write.mdx +54 -55
  108. package/docs/zh/guides/basic-features/debug/_meta.json +1 -0
  109. package/docs/zh/guides/basic-features/debug/rsdoctor.mdx +57 -0
  110. package/docs/zh/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +1 -1
  111. package/docs/zh/guides/basic-features/env-vars.mdx +1 -1
  112. package/docs/zh/guides/basic-features/render/_meta.json +1 -0
  113. package/docs/zh/guides/basic-features/render/ssg.mdx +210 -0
  114. package/docs/zh/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +16 -26
  115. package/docs/zh/guides/basic-features/render/ssr.mdx +309 -0
  116. package/docs/zh/guides/{advanced-features/ssr/stream.mdx → basic-features/render/streaming-ssr.mdx} +22 -37
  117. package/docs/zh/guides/basic-features/routes.mdx +251 -237
  118. package/docs/zh/guides/basic-features/static-assets/_meta.json +1 -0
  119. package/docs/zh/guides/basic-features/static-assets.mdx +3 -7
  120. package/docs/zh/guides/basic-features/testing/_meta.json +1 -0
  121. package/docs/zh/guides/basic-features/testing/cypress.mdx +95 -0
  122. package/docs/zh/guides/basic-features/testing/jest.mdx +148 -0
  123. package/docs/zh/guides/basic-features/testing/playwright.mdx +112 -0
  124. package/docs/zh/guides/basic-features/testing/vitest.mdx +100 -0
  125. package/docs/zh/guides/concept/entries.mdx +6 -3
  126. package/docs/zh/guides/deprecated.md +4 -0
  127. package/docs/zh/guides/get-started/quick-start.mdx +1 -1
  128. package/docs/zh/guides/get-started/tech-stack.mdx +8 -8
  129. package/docs/zh/guides/topic-detail/_meta.json +0 -6
  130. package/docs/zh/guides/topic-detail/generator/create/config.mdx +0 -10
  131. package/docs/zh/guides/topic-detail/generator/create/use.mdx +0 -1
  132. package/docs/zh/plugin/_meta.json +19 -0
  133. package/docs/zh/plugin/cli-plugins/_meta.json +1 -0
  134. package/docs/zh/plugin/cli-plugins/plugin-bff.mdx +5 -0
  135. package/docs/zh/plugin/cli-plugins/plugin-ssg.mdx +5 -0
  136. package/docs/zh/{guides/rsbuild-plugins → plugin/cli-plugins}/plugin-swc.mdx +7 -0
  137. package/docs/zh/plugin/cli-plugins/plugin-tailwind.mdx +5 -0
  138. package/docs/zh/plugin/cli-plugins.mdx +6 -0
  139. package/docs/zh/{guides/advanced-features/rsbuild-plugin.mdx → plugin/introduction.mdx} +38 -13
  140. package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/extend.mdx +1 -1
  141. package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/implement.mdx +3 -3
  142. package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/plugin-api.mdx +2 -2
  143. package/docs/zh/plugin/rsbuild-plugins/_meta.json +1 -0
  144. package/docs/zh/plugin/rsbuild-plugins.mdx +4 -0
  145. package/docs/zh/tutorials/first-app/c03-css.mdx +1 -1
  146. package/i18n.json +42 -6
  147. package/package.json +7 -6
  148. package/rspress.config.ts +1 -58
  149. package/src/components/Footer/index.tsx +1 -1
  150. package/src/pages/index.tsx +0 -1
  151. package/docs/en/apis/app/hooks/api/api.mdx +0 -80
  152. package/docs/en/apis/app/hooks/api/app.mdx +0 -12
  153. package/docs/en/apis/app/hooks/config/storybook.mdx +0 -37
  154. package/docs/en/guides/advanced-features/bff/type.mdx +0 -46
  155. package/docs/en/guides/advanced-features/eslint.mdx +0 -148
  156. package/docs/en/guides/advanced-features/ssg.mdx +0 -116
  157. package/docs/en/guides/advanced-features/ssr/_meta.json +0 -1
  158. package/docs/en/guides/advanced-features/ssr/index.mdx +0 -23
  159. package/docs/en/guides/advanced-features/ssr/stream.mdx +0 -248
  160. package/docs/en/guides/advanced-features/ssr/usage.mdx +0 -341
  161. package/docs/en/guides/advanced-features/ssr.mdx +0 -555
  162. package/docs/zh/apis/app/hooks/api/api.mdx +0 -81
  163. package/docs/zh/apis/app/hooks/api/app.mdx +0 -12
  164. package/docs/zh/apis/app/hooks/config/storybook.mdx +0 -38
  165. package/docs/zh/guides/advanced-features/bff/type.mdx +0 -46
  166. package/docs/zh/guides/advanced-features/eslint.mdx +0 -152
  167. package/docs/zh/guides/advanced-features/ssg.mdx +0 -116
  168. package/docs/zh/guides/advanced-features/ssr/_meta.json +0 -1
  169. package/docs/zh/guides/advanced-features/ssr/index.mdx +0 -23
  170. package/docs/zh/guides/advanced-features/ssr/usage.mdx +0 -329
  171. /package/docs/en/guides/advanced-features/{bff/index.mdx → bff.mdx} +0 -0
  172. /package/docs/en/guides/advanced-features/{code-split.mdx → page-performance/code-split.mdx} +0 -0
  173. /package/docs/en/guides/advanced-features/{inline-assets.mdx → page-performance/inline-assets.mdx} +0 -0
  174. /package/docs/en/guides/advanced-features/{optimize-bundle.mdx → page-performance/optimize-bundle.mdx} +0 -0
  175. /package/docs/en/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
  176. /package/docs/en/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
  177. /package/docs/en/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
  178. /package/docs/en/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
  179. /package/docs/en/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.mdx} +0 -0
  180. /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/_meta.json +0 -0
  181. /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook-list.mdx +0 -0
  182. /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook.mdx +0 -0
  183. /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/introduction.mdx +0 -0
  184. /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/lifecycle.mdx +0 -0
  185. /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/relationship.mdx +0 -0
  186. /package/docs/en/{guides → plugin}/rsbuild-plugins/plugin-esbuild.mdx +0 -0
  187. /package/docs/zh/guides/advanced-features/{bff/index.mdx → bff.mdx} +0 -0
  188. /package/docs/zh/guides/advanced-features/{code-split.mdx → page-performance/code-split.mdx} +0 -0
  189. /package/docs/zh/guides/advanced-features/{inline-assets.mdx → page-performance/inline-assets.mdx} +0 -0
  190. /package/docs/zh/guides/advanced-features/{optimize-bundle.mdx → page-performance/optimize-bundle.mdx} +0 -0
  191. /package/docs/zh/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -0
  192. /package/docs/zh/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
  193. /package/docs/zh/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
  194. /package/docs/zh/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
  195. /package/docs/zh/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
  196. /package/docs/zh/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.mdx} +0 -0
  197. /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/_meta.json +0 -0
  198. /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook-list.mdx +0 -0
  199. /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook.mdx +0 -0
  200. /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/introduction.mdx +0 -0
  201. /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/lifecycle.mdx +0 -0
  202. /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/relationship.mdx +0 -0
  203. /package/docs/zh/{guides → plugin}/rsbuild-plugins/plugin-esbuild.mdx +0 -0
@@ -2,20 +2,22 @@
2
2
  sidebar_position: 2
3
3
  ---
4
4
 
5
- # 路由方案
5
+ # 路由
6
6
 
7
- Modern.js 的路由基于 [React Router 6](https://reactrouter.com/en/main),并提供了多种类型的路由模式。根据不同 [入口](/guides/concept/entries) 类型,将路由分为三种模式,分别是**约定式路由**,**自控式路由**和**其他路由方案**。
7
+ Modern.js 的路由基于 [React Router 6](https://reactrouter.com/en/main),提供了基于文件约定的路由能力,并支持了业界流行的约定式路由模式:**嵌套路由**。当入口被识别为 [约定式路由](/guides/concept/entries.html#约定式路由) 时,Modern.js 会自动基于文件系统,生成对应的路由结构。
8
8
 
9
9
  :::note
10
- 本小节提到的路由,都是客户端路由,即 SPA 路由。
11
-
10
+ 本小节提到的路由,都是约定式路由。
12
11
  :::
13
12
 
14
- ## 约定式路由
13
+ ## 什么是嵌套路由
14
+
15
+ 嵌套路由是一种将 URL 分段与组件层次结构和数据耦合起来的路由模式。通常,URL 段会决定:
15
16
 
16
- `routes/` 为约定的入口,Modern.js 会自动基于文件系统,生成对应的路由结构。
17
+ - 页面上要渲染的布局
18
+ - 这些布局的数据依赖
17
19
 
18
- Modern.js 支持了业界流行的约定式路由模式:**嵌套路由**,使用嵌套路由时,页面的路由 与 UI 结构是相呼应的,我们将会详细介绍这种路由模式。
20
+ 因此,使用嵌套路由时,页面的路由与 UI 结构是相呼应的,我们将会详细介绍这种路由模式。
19
21
 
20
22
  ```bash
21
23
  /user/johnny/profile /user/johnny/posts
@@ -28,61 +30,44 @@ Modern.js 支持了业界流行的约定式路由模式:**嵌套路由**,使
28
30
  +------------------+ +-----------------+
29
31
  ```
30
32
 
31
- ### 路由文件约定
33
+ ## 路由文件约定
32
34
 
33
- 在`routes/` 目录下,目录名会作为路由 url 的映射,Modern.js 有两个文件约定 `layout.[jt]sx` 和 `page.[jt]sx`(后面简写为 `.tsx`)。这两个文件决定了应用的布局层次,其中 `layout.tsx` 中作为布局组件,`page.tsx` 作为内容组件,是整条路由的叶子节点(一条路由有且仅有一个叶子节点,且必须以叶子节点结尾)。
34
-
35
- 例如以下目录结构:
35
+ 在 `routes/` 目录下,子目录名会作为路由 URL 的映射,Modern.js 有两个文件约定 `layout.tsx` 和 `page.tsx`。这两个文件决定了应用的布局层次,其中:
36
36
 
37
- ```bash
38
- .
39
- └── routes
40
- ├── page.tsx
41
- └── user
42
- └── page.tsx
43
- ```
37
+ - `page.tsx` 为内容组件,所在目录下存在该文件时,对应的路由 URL 可访问。
38
+ - `layout.tsx` 为布局组件,控制所在目录下所有子路由的布局,使用 `<Outlet>` 表示子组件。
44
39
 
45
- 会产出下面两条路由:
40
+ :::tip
41
+ `.ts`、`.js`、`.jsx` 或 `.tsx` 文件扩展名可用于上述约定文件。
42
+ :::
46
43
 
47
- - `/`
48
- - `/user`
44
+ ### Page
49
45
 
50
- 当添加 `layout.tsx` 后, 假设有以下目录
46
+ `<Page>` 组件是指 `routes/` 目录下所有 `page.tsx` 文件,也是所有路由的叶子组件。除了通配路由外,任何路由都应该由 `<Page>` 组件结束。
51
47
 
52
- :::info
53
- 这里 `routes/layout.tsx` 会作为 `/` 路由下所有组件的布局组件使用, `routes/user/layout.tsx` 会作为 `/user` 路由下所有路由组件的布局组件使用。
48
+ ```tsx title=routes/page.tsx
49
+ export default () => {
50
+ return <div>Hello world</div>
51
+ };
52
+ ```
54
53
 
55
- :::
54
+ 当应用中存在以下目录结构时:
56
55
 
57
56
  ```bash
58
57
  .
59
58
  └── routes
60
- ├── layout.tsx
61
59
  ├── page.tsx
62
60
  └── user
63
- ├── layout.tsx
64
61
  └── page.tsx
65
62
  ```
66
63
 
67
- 当路由为 `/` 时,会有以下 UI 布局:
64
+ 会产出下面两条路由:
68
65
 
69
- ```tsx
70
- <Layout>
71
- <Page />
72
- </Layout>
73
- ```
66
+ - `/`
67
+ - `/user`
74
68
 
75
- 同样,`routes/user/layout.tsx` 会作为 `/user` 路由下所有组件的布局组件使用。当路由为 `/user` 时, 会有以下 UI 布局:
76
69
 
77
- ```tsx
78
- <Layout>
79
- <UserLayout>
80
- <UserPage />
81
- </UserLayout>
82
- </Layout>
83
- ```
84
-
85
- #### Layout
70
+ ### Layout
86
71
 
87
72
  `<Layout>` 组件是指 `routes/` 目录下所有 `layout.tsx` 文件,它们表示对应路由片段的布局,使用 `<Outlet>` 表示子组件。
88
73
 
@@ -99,11 +84,10 @@ export default () => {
99
84
  ```
100
85
 
101
86
  :::note
102
- `<Outlet>` 是 React Router 6 中新的 API,详情可以查看 [Outlet](https://reactrouter.com/en/main/components/outlet#outlet).
103
-
87
+ `<Outlet>` 是 React Router 6 中提供的 API,详情可以查看 [Outlet](https://reactrouter.com/en/main/components/outlet#outlet)
104
88
  :::
105
89
 
106
- 为了方便介绍 `<Layout>` 与 `<Outlet>` 的关系,以下面的文件目录举例:
90
+ 不同目录结构下,`<Outlet>` 所代表的组件也不同。为了方便介绍 `<Layout>` 与 `<Outlet>` 的关系,以下面的文件目录举例:
107
91
 
108
92
  ```bash
109
93
  .
@@ -117,7 +101,7 @@ export default () => {
117
101
  └── page.tsx
118
102
  ```
119
103
 
120
- 1. 当路由为 `/` 时,`routes/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/page.tsx` 中导出的组件,生成以下 UI 结构:
104
+ 1. 当路由为 `/` 时,`routes/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/page.tsx` 中导出的组件,路由的 UI 结构为:
121
105
 
122
106
  ```tsx
123
107
  <Layout>
@@ -125,7 +109,7 @@ export default () => {
125
109
  </Layout>
126
110
  ```
127
111
 
128
- 2. 当路由为 `/blog` 时,`routes/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/blog/page.tsx` 中导出的组件,生成以下 UI 结构:
112
+ 2. 当路由为 `/blog` 时,`routes/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/blog/page.tsx` 中导出的组件,路由的 UI 结构为:
129
113
 
130
114
  ```tsx
131
115
  <Layout>
@@ -133,7 +117,7 @@ export default () => {
133
117
  </Layout>
134
118
  ```
135
119
 
136
- 3. 当路由为 `/user` 时,`routes/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/user/layout.tsx` 中导出的组件。`routes/user/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/user/page.tsx` 中导出的组件。生成以下 UI 结构:
120
+ 3. 当路由为 `/user` 时,`routes/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/user/layout.tsx` 中导出的组件。`routes/user/layout.tsx` 中的 `<Outlet>` 代表的是 `routes/user/page.tsx` 中导出的组件,路由的 UI 结构为:
137
121
 
138
122
  ```tsx
139
123
  <Layout>
@@ -145,43 +129,16 @@ export default () => {
145
129
 
146
130
  总结而言,如果子路由的文件目录下存在 `layout.tsx`,上一级 `layout.tsx` 中的 `<Outlet>` 即为子路由文件目录下的 `layout.tsx` ,否则为子路由文件目录下的 `page.tsx`。
147
131
 
148
- #### Page
149
-
150
- 所有的路由,理论上都应该由 `<Page>` 组件结束。在 `page.tsx` 文件内,如果开发者引入 `<Outlet>` 组件,不会有任何效果。
151
-
152
- #### Config
153
-
154
- 每个 `Layout`, `$` 或 `Page` 文件都可以定义一个自己的 `config` 文件,如 `page.config.ts`,该文件中我们约定了一个具名导出 `handle`,
155
- 这个字段中你可以定义任意属性:
156
-
157
- ```ts title="routes/page.config.ts"
158
- export const handle = {
159
- breadcrumbName: 'profile',
160
- };
161
- ```
162
-
163
- 定义的这些属性可以通过 [`useMatches`](https://reactrouter.com/en/main/hooks/use-matches) hook 获取:
164
-
165
- ```ts title="routes/layout.ts"
166
- export default () => {
167
- const matches = useMatches();
168
- const breadcrumbs = matches.map(
169
- matchedRoute => matchedRoute?.handle?.breadcrumbName,
170
- );
171
- return <Breadcrumb names={breadcrumbs}></Breadcrumb>;
172
- };
173
- ```
174
-
175
- ### 动态路由
132
+ ## 动态路由
176
133
 
177
134
  通过 `[]` 命名的文件目录,生成的路由会作为动态路由。例如以下文件目录:
178
135
 
179
136
  ```bash
137
+ .
180
138
  └── routes
181
- ├── [id]
182
- │ └── page.tsx
183
139
  ├── blog
184
- └── page.tsx
140
+    └── [id]
141
+ │   └── page.tsx
185
142
  └── page.tsx
186
143
  ```
187
144
 
@@ -189,48 +146,71 @@ export default () => {
189
146
 
190
147
  在组件中,可以通过 [useParams](/apis/app/runtime/router/router#useparams) 获取对应命名的参数。
191
148
 
192
- 在 loader 中,params 会作为 [loader](/guides/basic-features/data/data-fetch#loader-函数) 的入参,通过 `params.xxx` 可以获取。
149
+ ```tsx
150
+ import { useParams } from '@modern-js/runtime/router';
151
+
152
+ function Blog() {
153
+ const { id } = useParams();
154
+ return <div>current blog ID is: {id}</div>;
155
+ }
156
+ export default Blog;
157
+ ```
193
158
 
194
- ### 动态可选路由
159
+ ## 动态可选路由
195
160
 
196
161
  通过 `[$]` 命名的文件目录,生成的路由会作为动态可选路由。例如以下文件目录:
197
162
 
198
163
  ```bash
164
+ .
199
165
  └── routes
200
- ├── user
166
+ ├── blog
201
167
  │ └── [id$]
202
168
  │ └── page.tsx
203
- ├── blog
204
- │ └── page.tsx
205
169
  └── page.tsx
206
170
  ```
207
171
 
208
172
  `routes/user/[id$]/page.tsx` 文件会转为 `/user/:id?` 路由。`/user` 下的所有路由都会匹配到该路由,并且 `id` 参数可选存在。通常在区分**创建**与**编辑**时,可以使用该路由。
209
173
 
210
- 在组件中,可以通过 [useParams](/apis/app/runtime/router/router#useparams) 获取对应命名的参数。
174
+ ```tsx
175
+ import { useParams } from '@modern-js/runtime/router';
176
+
177
+ function Blog() {
178
+ const { id } = useParams();
179
+ if (id) {
180
+ return <div>current blog ID is: {id}</div>;
181
+ }
182
+
183
+ return <div>create new blog</div>;
184
+ }
185
+ export default Blog;
186
+ ```
211
187
 
212
- 在 loader 中,params 会作为 [loader](/guides/basic-features/data/data-fetch#loader-函数) 的入参,通过 `params.xxx` 可以获取。
213
188
 
214
- ### 通配路由
189
+ ## 通配路由
215
190
 
216
- 如果在 routes 目录下创建 `$.tsx` 文件,该文件会作为通配路由组件,当没有匹配的路由时,会渲染该路由组件。
191
+ 如果在某个子目录下存在 `$.tsx` 文件,该文件会作为通配路由组件,当没有匹配的路由时,会渲染该路由组件。
217
192
 
218
193
  :::note
219
- `$.tsx` 可以认为是一种特殊的 `page` 路由组件,当前目录下有 `layout` 组件时,`$.tsx`,会作为 `layout` 的子组件渲染。
194
+ `$.tsx` 可以认为是一种特殊的 `<Page>` 组件,如果路由无法匹配,则 `$.tsx` 会作为 `<Layout>` 的子组件渲染。
195
+ :::
196
+
197
+ :::warning
198
+ 如果当前目录下不存在 `<Layout>` 组件时,则 `$.tsx` 不会生效。
220
199
  :::
221
200
 
222
201
  例如以下目录结构:
223
202
 
224
203
  ```bash
204
+ .
225
205
  └── routes
226
206
  ├── blog
227
207
  │ ├── $.tsx
228
208
  │ └── layout.tsx
229
- └── layout.tsx
209
+ ├── layout.tsx
230
210
  └── page.tsx
231
211
  ```
232
212
 
233
- 当访问任何匹配不到的路径时(如 `/blog/a`),都会渲染 `routes/blog/$.tsx` 组件,因为这里有 `layout.tsx`,渲染的 UI 如下:
213
+ 当你访问 `/blog/a` 时,无法匹配到任意路由,则页面会渲染 `routes/blog/$.tsx` 组件,路由的 UI 结构为:
234
214
 
235
215
  ```tsx
236
216
  <RootLayout>
@@ -246,16 +226,70 @@ export default () => {
246
226
 
247
227
  ```ts title="$.tsx"
248
228
  import { useParams } from '@modern-js/runtime/router';
249
- // 当 path 是 `/aaa/bbb` 时
250
- const params = useParams();
251
- params['*']; // => 'aaa/bbb'
229
+
230
+ function Blog() {
231
+ // path 是 `/blog/aaa/bbb` 时
232
+ const params = useParams();
233
+ console.log(params) // ---> { '*': 'aaa/bbb' }
234
+
235
+ return <div>current blog URL is {params["*"]}</div>;
236
+ }
237
+ export default Blog;
238
+ ```
239
+
240
+ ### 定制 404 页面
241
+
242
+ 通配路由可以被添加到 `routes/` 目录下的任意子目录中,一种常见的使用场景是通过 `$.tsx` 文件去定制任意层级的 404 内容。
243
+
244
+ 例如你需要对所有未匹配到的路由,都展示一个 404 页面,可以添加 `routes/$.tsx` 文件:
245
+
246
+ ```bash
247
+ .
248
+ └── routes
249
+ ├── $.tsx
250
+ ├── blog
251
+ │   └── [id$]
252
+ │   └── page.tsx
253
+ ├── layout.tsx
254
+ └── page.tsx
252
255
  ```
253
256
 
254
- `$.tsx` 可以加入到 `routes` 目录下的任意目录中,一个常见的使用示例是添加 `routes/$.tsx` 文件去定制任意层级的 404 内容。
257
+ ```tsx
258
+ function Page404() {
259
+ return <div>404 Not Found</div>;
260
+ }
261
+ export default Page404;
262
+ ```
263
+
264
+ 此时,当访问除了 `/` 或 `/blog/*` 以外的路由时,都会匹配到 `routes/$.tsx` 组件,展示 404 页面。
265
+
266
+ ## 路由句柄配置
255
267
 
256
- ### 无路径布局
268
+ 某些场景下,每个路由会拥有属于自己的数据,应用需要在其他组件中获取匹配到的路由的这些数据。一个常见的例子是在布局中获取到匹配路由的面包屑信息。
269
+
270
+ Modern.js 提供了独立的约定,每个 `Layout`, `$` 或 `Page` 文件都可以定义一个自己的 `config` 文件,如 `page.config.ts`,该文件中我们约定了一个具名导出 `handle`,这个字段中你可以定义任意属性:
271
+
272
+ ```ts title="routes/page.config.ts"
273
+ export const handle = {
274
+ breadcrumbName: 'profile',
275
+ };
276
+ ```
257
277
 
258
- 当目录名以 \_\_ 开头时,对应的目录名不会转换为实际的路由路径,例如以下文件目录:
278
+ 定义的这些属性可以通过 [`useMatches`](https://reactrouter.com/en/main/hooks/use-matches) hook 获取。
279
+
280
+ ```ts title="routes/layout.ts"
281
+ export default () => {
282
+ const matches = useMatches();
283
+ const breadcrumbs = matches.map(
284
+ matchedRoute => matchedRoute?.handle?.breadcrumbName,
285
+ );
286
+ return <Breadcrumb names={breadcrumbs}></Breadcrumb>;
287
+ };
288
+ ```
289
+
290
+ ## 无路径布局
291
+
292
+ 当目录名以 `__` 开头时,对应的目录名不会转换为实际的路由路径,例如以下文件目录:
259
293
 
260
294
  ```bash
261
295
  .
@@ -264,19 +298,19 @@ params['*']; // => 'aaa/bbb'
264
298
  │ ├── layout.tsx
265
299
  │ ├── login
266
300
  │ │ └── page.tsx
267
- │ └── signup
301
+ │ └── sign
268
302
  │ └── page.tsx
269
303
  ├── layout.tsx
270
304
  └── page.tsx
271
305
  ```
272
306
 
273
- Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组件会作为 `login/page.tsx` 和 `signup/page.tsx` 的布局组件,但`__auth` 不会作为路由路径片段。
307
+ Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组件会作为 `login/page.tsx` 和 `sign/page.tsx` 的布局组件,但`__auth` 不会作为路由路径片段出现在用户访问的 URL 中。
274
308
 
275
309
  当需要为某些类型的路由,做独立的布局,或是想要将路由做归类时,这一功能非常有用。
276
310
 
277
- ### 无布局路径
311
+ ## 无布局路径
278
312
 
279
- 有些情况下,项目需要较为复杂的路由,但这些路由又不存在独立的 UI 布局,如果像普通文件目录那边创建路由会导致目录层级较深。
313
+ 有些情况下,项目需要较为复杂的路由,但这些路由又不存在独立的 UI 布局,如果像普通文件目录那样创建路由会导致目录层级较深。
280
314
 
281
315
  因此 Modern.js 支持了通过 `.` 来分割路由片段,代替文件目录。例如,当需要 `/user/profile/2022/edit` 时,可以直接创建如下文件:
282
316
 
@@ -292,15 +326,93 @@ Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组
292
326
 
293
327
  ```tsx
294
328
  <RootLayout>
295
- <UserProfileEdit /> // routes/user.profile.[id].edit/page.tsx
329
+ {/* routes/user.profile.[id].edit/page.tsx */}
330
+ <UserProfileEdit />
296
331
  </RootLayout>
297
332
  ```
298
333
 
299
- ### Loading (Experimental)
334
+ ## 路由重定向
335
+
336
+ 某些应用中,可能需要根据用户的身份信息,或是其他数据条件,选择重定向到其他路由。在 Modern.js 中,你可以使用 [`Data Loader`](/guides/basic-features/data/data-fetch) 文件来获取数据,或是和传统 React 组件那样,在 `useEffect` 中请求数据。
337
+
338
+ ### 在 Data Loader 中重定向
339
+
340
+ 在任意的 `page.tsx` 同级目录中创建,`page.data.ts` 文件,这个文件就是该路由的 Data Loader。在 Data Loader 中,你可以通过调用 `redirect` API 来完成路由的重定向。
341
+
342
+ ```ts title="routes/user/page.data.ts"
343
+ import { redirect } from '@modern-js/runtime/router';
344
+
345
+ export const loader = () => {
346
+ const user = await getUser();
347
+ if (!user) {
348
+ return redirect('/login');
349
+ }
350
+ return null;
351
+ };
352
+ ```
353
+
354
+ ### 在组件中重定向
355
+
356
+ 在组件内做重定向,则可以通过 `useNavigate` hook,示例如下:
357
+
358
+ ```ts title="routes/user/page.ts"
359
+ import { useNavigate } from '@modern-js/runtime/router';
360
+ import { useEffect } from 'react';
361
+
362
+ export default () => {
363
+ const navigate = useNavigate();
364
+ useEffect(() => {
365
+ getUser().then(user => {
366
+ if (!user) {
367
+ navigate('/login');
368
+ }
369
+ });
370
+ });
371
+
372
+ return <div>Hello World</div>;
373
+ };
374
+ ```
375
+
376
+ ## 错误处理
377
+
378
+ `routes/` 下每一层目录中,开发者同样可以定义一个 `error.tsx` 文件,默认导出一个 `<ErrorBoundary>` 组件。当路由目录下存在该组件时,组件渲染出错会被 `ErrorBoundary` 组件捕获。
379
+
380
+ `<ErrorBoundary>` 可以返回出错时的 UI 视图,当前层级未声明 `<ErrorBoundary>` 组件时,错误会向上冒泡到更上层的组件,直到被捕获或抛出错误。同时,当组件出错时,只会影响捕获到该错误的路由组件及子组件,其他组件的状态和视图不受影响,可以继续交互。
381
+
382
+ {/* Todo API 路由 */}
300
383
 
301
- `routes/` 下每一层目录中,开发者可以创建 `loading.tsx` 文件,默认导出一个 `<Loading>` 组件。
384
+ `<ErrorBoundary>` 组件内,可以使用 [useRouteError](/apis/app/runtime/router/router#userouteerror) 获取的错误的具体信息:
302
385
 
303
- 当路由目录下存在该组件和 `layout` 组件时,这一级子路由下所有的路由切换时,都会以该 `<Loading>` 组件作为 JS Chunk 加载时的 Fallback UI。例如以下文件目录:
386
+ ```tsx
387
+ import { useRouteError } from '@modern-js/runtime/router';
388
+
389
+ const ErrorBoundary = () => {
390
+ const error = useRouteError();
391
+ return (
392
+ <div>
393
+ <h1>{error.status}</h1>
394
+ <h2>{error.message}</h2>
395
+ </div>
396
+ );
397
+ };
398
+ export default ErrorBoundary;
399
+ ```
400
+
401
+ ## Loading (Experimental)
402
+
403
+ :::info Experimental
404
+ 此功能当前是实验性功能,后续 API 可能有调整。
405
+ :::
406
+
407
+ 在约定式路由下, Modern.js 会根据路由,自动地对路由进行分片(每一个路由都作为单独的 JS Chunk 进行加载),当用户访问具体的路由时,再自动加载对应的分片。这样可以有效地减少首屏加载的时间。但这也带来了一个问题,当用户访问一个路由时,如果该路由对应的分片还未加载完成,就会出现白屏的情况。
408
+
409
+ Modern.js 支持通过 `loading.tsx` 文件来解决这个问题,`routes/` 下每一层目录中,都可以创建 `loading.tsx` 文件,默认导出一个 `<Loading>` 组件。
410
+
411
+ :::warning
412
+ 如果当前目录下不存在 `<Layout>` 组件时,则 `loading.tsx` 不会生效。为了保证用户体验,Modern.js 推荐每个应用添加根 Loading 组件。
413
+ :::
414
+
415
+ 当路由目录下同时存在该组件和 `layout` 组件时,这一级路由下所有的子路由切换时,会先展示 `loading.tsx` 中导出的组件 UI,直到对应的 JS Chunk 加载完成。例如以下文件目录:
304
416
 
305
417
  ```bash
306
418
  .
@@ -314,9 +426,9 @@ Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组
314
426
  └── page.tsx
315
427
  ```
316
428
 
317
- 当定义 `loading.tsx` 时,就相当于以下布局:
429
+ 当定义 `loading.tsx` 时,当路由从 `/` 跳转到 `/blog`,或从 `/blog` 跳转到 `/blog/123` 时,如果路由对应的 JS Chunk 还未加载,都会先展示 `loading.tsx` 中导出的组件 UI。相当于最终的 UI 结构如下:
318
430
 
319
- ```tsx title=当路由为"/"时
431
+ ```tsx title=当路由为 "/"
320
432
  <Layout>
321
433
  <Suspense fallback={<Loading />}>
322
434
  <Page />
@@ -324,7 +436,7 @@ Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组
324
436
  </Layout>
325
437
  ```
326
438
 
327
- ```tsx title=当路由为"/blog"时
439
+ ```tsx title=当路由为 "/blog"
328
440
  <Layout>
329
441
  <Suspense fallback={<Loading />}>
330
442
  <BlogPage />
@@ -332,7 +444,7 @@ Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组
332
444
  </Layout>
333
445
  ```
334
446
 
335
- ```tsx title=当路由为"/blog/123"时
447
+ ```tsx title=当路由为 "/blog/123"
336
448
  <Layout>
337
449
  <Suspense fallback={<Loading />}>
338
450
  <BlogIdPage />
@@ -340,72 +452,41 @@ Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组
340
452
  </Layout>
341
453
  ```
342
454
 
343
- :::info
344
- 当目录的 Layout 组件不存在时,该目录下的 Loading 组件也不会生效。
345
- Modern.js 建议必须有根 Layout 和根 Loading。
455
+ ## 预加载
346
456
 
347
- :::
457
+ 大多数切换路由时白屏的情况,都可以通过定义 `<Loading>` 组件来优化体验。Modern.js 也支持在 `<Link>` 组件上定义 `prefetch` 属性,提前对静态资源和数据进行加载。
348
458
 
349
- 当路由从 `/` 跳转到 `/blog` 时,如果 `blog/page` 组件的 JS Chunk 还未加载,则会先展示 `loading.tsx` 中导出的组件 UI。
459
+ 对于有更高性能要求的应用,预加载可以进一步提升用户体验,减少展示 `<Loading>` 组件的时间:
350
460
 
351
- 同理,当路由从 `/` 或者 `/blog` 跳转到 `/blog/123` 时,如果 `blog/[id]/page` 组件的 JS Chunk 还未加载,也会先展示 `loading.tsx` 中导出的组件 UI。
352
-
353
- ### 路由重定向
354
-
355
- 可以使用 [`Data Loader`](/guides/basic-features/data/data-fetch) 文件做路由的重定向。如有文件 `routes/user/page.tsx`,想对这个文件对应的路由做重定向,可以创建 `routes/user/page.data.ts` 文件:
356
-
357
- ```ts title="routes/user/page.data.ts"
358
- import { redirect } from '@modern-js/runtime/router';
359
-
360
- export const loader = () => {
361
- const user = await getUser();
362
- if (!user) {
363
- return redirect('/login');
364
- }
365
- return null;
366
- };
461
+ ```tsx
462
+ <Link prefetch="intent" to="page">
367
463
  ```
368
464
 
369
- 在组件内做重定向,则可以通过 `useNavigate` hook,示例如下:
465
+ :::tip
370
466
 
371
- ```ts title="routes/user/page.ts"
372
- import { useNavigate } from '@modern-js/runtime/router';
467
+ 对数据的预加载目前只会预加载 SSR 项目中 [Data Loader](/guides/basic-features/data/data-fetch) 中返回的数据。
373
468
 
374
- export default () => {
375
- const navigate = useNavigate();
376
- navigate('/login');
377
- };
378
- ```
469
+ :::
379
470
 
380
- ### 错误处理
471
+ `prefetch` 属性有三个可选值:
381
472
 
382
- `routes/` 下每一层目录中,开发者同样可以定义一个 `error.tsx` 文件,默认导出一个 `<ErrorBoundary>` 组件。
473
+ - `none`, 默认值,不会做 prefetch,没有任何额外的行为。
474
+ - `intent`,这是我们推荐大多数场景下使用的值,当你把鼠标放在 Link 上时,会自动开始加载对应的分片和 Data Loader 中定义的数据,当鼠标移开时,会自动取消加载。在我们的测试中,即使是快速点击,也能减少大约 200ms 的加载时间。
475
+ - `render`,当 `<Link>` 组件渲染时,就会加载对应的分片和 Data Loader 中定义的数据。
383
476
 
384
- 当有路由目录下存在该组件时,组件渲染出错会被 `ErrorBoundary` 组件捕获。
477
+ :::details 值为 render 和不做路由分片的区别
478
+ - `render` 加载路由分片的时机是可控的,只有在 `<Link>` 组件进入视窗时才触发,可以通过控制 `<Link>` 组件的渲染位置来控制分片加载时机。
479
+ - `render` 仅在空闲时对静态资源进行加载,不占用重要模块的加载时间。
480
+ - 除了预加载路由分片,`render` 在 SSR 项目中还会发起数据预取。
385
481
 
386
- `<ErrorBoundary>` 可以返回出错时的 UI 视图,当前层级未声明 `<ErrorBoundary>` 组件时,错误会向上冒泡到更上层的组件,直到被捕获或抛出错误。同时,当组件出错时,只会影响捕获到该错误的路由组件及子组件,其他组件的状态和视图不受影响,可以继续交互。
482
+ :::
387
483
 
388
- {/* Todo API 路由 */}
389
484
 
390
- `<ErrorBoundary>` 组件内,可以使用 [useRouteError](/apis/app/runtime/router/router#userouteerror) 获取的错误的具体信息:
485
+ ## 运行时配置
391
486
 
392
- ```tsx
393
- import { useRouteError } from '@modern-js/runtime/router';
394
- const ErrorBoundary = () => {
395
- const error = useRouteError();
396
- return (
397
- <div>
398
- <h1>{error.status}</h1>
399
- <h2>{error.message}</h2>
400
- </div>
401
- );
402
- };
403
- export default ErrorBoundary;
404
- ```
487
+ {/* Todo 移到动运行时配置章节 */}
405
488
 
406
- ### 运行时配置
407
-
408
- 在每个根 `Layout` 组件中(`routes/layout.ts`),可以动态地定义运行时配置:
489
+ 在根 `<Layout>` 组件中(`routes/layout.ts`),可以动态地定义运行时配置:
409
490
 
410
491
  ```tsx title="src/routes/layout.tsx"
411
492
  // 定义运行时配置
@@ -427,7 +508,9 @@ export const config = (): AppConfig => {
427
508
  };
428
509
  ```
429
510
 
430
- ### 渲染前的钩子
511
+ ## 渲染前的钩子
512
+
513
+ {/* Todo 移到动运行时配置章节 */}
431
514
 
432
515
  在有些场景下,需要在应用渲染前做一些操作,可以在 `routes/layout.tsx` 中定义 `init` 钩子,`init` 在客户端和服务端均会执行,基本使用示例如下:
433
516
 
@@ -490,91 +573,22 @@ export const init = (context: RuntimeContext) => {
490
573
  };
491
574
  ```
492
575
 
493
- ### 预加载
494
-
495
- 在约定式路由下, Modern.js 会根据路由,自动地对路由进行分片。当用户访问具体的路由时,会自动加载对应的分片,这样可以有效地减少首屏加载的时间。但这也带来了一个问题,当用户访问一个路由时,如果该路由对应的分片还未加载完成,就会出现白屏的情况。
496
- 这种情况下你可以通过定义 `Loading` 组件,在静态资源加载完成前,展示一个自定义的 `Loading` 组件。
497
-
498
- 为了进一步提升用户体验,减少 loading 的时间,Modern.js 支持在 Link 组件上定义 `prefetch` 属性,可以提前对静态资源和数据进行加载:
499
-
500
- ```tsx
501
- <Link prefetch="intent" to="page">
502
- ```
503
-
504
- :::info
505
-
506
- - 该功能目前仅在 Webpack 项目中支持,Rspack 项目暂不支持。
507
- - 对数据的预加载目前只会预加载 SSR 项目中 [Data Loader](/guides/basic-features/data/data-fetch) 中返回的数据。
508
-
509
- :::
510
-
511
- `prefetch` 属性有三个可选值:
512
-
513
- - `none`, 默认值,不会做 prefetch,没有任何额外的行为。
514
- - `intent`,这是我们推荐大多数场景下使用的值,当你把鼠标放在 Link 上时,会自动开始加载对应的分片和 Data Loader 中定义的数据,当鼠标移开时,会自动取消加载。在我们的测试中,即使是快速点击,也能减少大约 200ms 的加载时间。
515
- - `render`,当 Link 组件渲染时,就会加载对应的分片和 Data Loader 中定义的数据。
516
-
517
- #### 常见问题
518
-
519
- 1. 使用 `render` 和不根据路由做静态资源分片的区别?
520
-
521
- - 使用 `render` 可以指定哪些路由在首屏时,进行加载,同时你可以通过对渲染的控制,仅当 `Link` 组件进入到可视区域时,才对 `Link` 组件进行渲染。
522
- - 使用 `render`,仅在空闲时对静态资源进行加载,不会与首屏静态资源抢占网络。
523
- - 在 SSR 场景下,也会对数据进行预取。
524
-
525
576
  import Motivation from '@site-docs/components/convention-routing-motivation';
526
577
 
527
578
  <Motivation />
528
579
 
529
- import Practice from '@site-docs/components/routes-practice';
580
+ ## 常见问题
530
581
 
531
- <Practice />
582
+ 1. 为什么要提供 `@modern-js/runtime/router` 来导出 React Router API ?
532
583
 
533
- ## 自控式路由
584
+ 可以发现,在文档中所有的代码用例都是使用 `@modern-js/runtime/router` 包导出的 API,而不是直接使用 React Router 包导出的 API。那两者有什么区别呢?
534
585
 
535
- `src/App.tsx` 为约定的入口,Modern.js 不会对路由做额外的操作,开发者可以自行使用 [React Router 6](https://reactrouter.com/en/main) API 进行开发,例如:
586
+ 首先,在 `@modern-js/runtime/router` 中导出的 API React Router 包的 API 是完全一致的,如果某个 API 使用出现问题,请先检查 React Router 的文档和 Issues。
536
587
 
537
- ```ts title="src/App.tsx"
538
- import { BrowserRouter, Route, Routes } from '@modern-js/runtime/router';
539
-
540
- export default () => {
541
- return (
542
- <BrowserRouter>
543
- <Routes>
544
- <Route index element={<div>index</div>} />
545
- <Route path="about" element={<div>about</div>} />
546
- </Routes>
547
- </BrowserRouter>
548
- );
549
- };
550
- ```
588
+ 在使用约定式路由的情况下,务必使用 `@modern-js/runtime/router` 中的 API,不直接使用 React Router 的 API。因为 Modern.js 内部会安装 React Router,如果应用中使用了 React Router 的 API,可能会导致两个版本的 React Router 同时存在,出现不符合预期的行为。
551
589
 
552
590
  :::note
553
- Modern.js 默认对约定式路由做了一系列资源加载及渲染上的优化,并且提供了开箱即用的 SSR 能力。而在使用自控路由时,这些能力都需要开发者自行封装。我们推荐开发者使用约定式路由。
591
+ 如果应用中必须直接使用 React Router 包的 API,例如部分路由行为被封装在统一的 npm 包中,那应用可以通过设置 [`source.alias`](/configure/app/source/alias),将 `react-router` `react-router-dom` 统一指向项目的依赖,避免两个版本的 React Router 同时存在的问题。
554
592
  :::
555
593
 
556
- ## 其他路由方案
557
-
558
- 默认情况下,Modern.js 会开启内置的路由方案,即 React Router。
559
-
560
- ```js
561
- export default defineConfig({
562
- runtime: {
563
- router: true,
564
- },
565
- });
566
- ```
567
-
568
- 如上述配置,当开启 [`runtime.router`](/configure/app/runtime/router) 配置时,Modern.js 会从 `@modern-js/runtime/router` 命名空间导出 React Router 的 API 供开发者使用,保证开发者和 Modern.js 中使用同一份代码,并自动根据 router 配置包裹 `Provider` 组件。另外,这种情况下,React Router 的代码会被打包到 JS 产物中。
569
-
570
- 如果项目已经有自己的路由方案,或者不需要使用客户端路由,可以关闭这个功能。
571
-
572
- ```js
573
- export default defineConfig({
574
- runtime: {
575
- router: false,
576
- },
577
- });
578
- ```
579
594
 
580
- 如上述配置, 如果关闭了 [`runtime.router`](/configure/app/runtime/router) 配置,并直接使用 `react-router-dom` 进行项目路由管理时,还需要根据 React Router 文档自行包裹 `Provider`。