@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
@@ -1,32 +1,18 @@
1
1
  ---
2
- title: Data Fetching
3
2
  sidebar_position: 3
4
3
  ---
5
4
 
6
5
  # Data Fetching
7
6
 
8
- Modern.js provides out-of-the-box data fetching capabilities,developers can fetch data in the project through these APIs.
7
+ Modern.js provides out-of-the-box data fetching capabilities. Developers can use these APIs to fetch data in their projects. It's important to note that these APIs do not help the application make requests but assist developers in managing data better and improving project performance.
9
8
 
10
- It should be noted that these APIs do not help applications initiate requests, but rather help developers better manage data and improve project performance.
11
-
12
- ## Data Loader (Recommended)
13
-
14
- Modern.js recommends using [conventional routing](/guides/basic-features/routes) for routing management. Through Modern.js's [conventional (nested) routing](/guides/basic-features/routes#conventional-routing), each routing component (`layout.ts` or `page.ts`) can have a same-named `loader` file. The `loader` file needs to export a function that will be executed before the component is rendered to provide data for the routing component.
15
-
16
- :::info
17
- Modern.js v1 supports fetching data via [useLoader](</guides/basic-features/data/data-fetch.html#useloader-(old-version)>), which is no longer the recommended usage. We do not recommend mixing the two except during the migration process.
18
-
19
- :::
20
-
21
- :::warning
22
- - In the previous version, Modern.js Data Loader was defined in the `loader` file. In later versions, we recommend defining it in the `data` file, while we will maintain compatibility with the `loader` file.
23
- - In the `data` file, the corresponding `loader` needs to be exported with a name。
9
+ ## What is Data Loader
24
10
 
11
+ :::note
12
+ In Modern.js v1 projects, data was fetched using `useLoader`. This is no longer the recommended approach; we suggest migrating to Data Loader.
25
13
  :::
26
14
 
27
- ### Basic Example
28
-
29
- Routing components such as `layout.ts` or `page.ts` can define a same-named `loader` file. The function exported by the `data` file provides the data required by the component, and then the data is obtained in the routing component through the `useLoaderData` function, as shown in the following example:
15
+ Modern.js recommends managing routes using [conventional routing](/guides/basic-features/routes). Each route component (`layout.ts`, `page.ts`, or `$.tsx`) can have a same-named `.data` file. These files can export a `loader` function, known as Data Loader, which executes before the corresponding route component renders to provide data for the component. Here is an example:
30
16
 
31
17
  ```bash
32
18
  .
@@ -39,17 +25,7 @@ Routing components such as `layout.ts` or `page.ts` can define a same-named `loa
39
25
  └── page.data.ts
40
26
  ```
41
27
 
42
- Define the following code in the file:
43
-
44
- ```ts title="routes/user/page.tsx"
45
- import { useLoaderData } from '@modern-js/runtime/router';
46
- import type { ProfileData } from './page.data.ts';
47
-
48
- export default function UserPage() {
49
- const profileData = useLoaderData() as ProfileData;
50
- return <div>{profileData}</div>;
51
- }
52
- ```
28
+ In the `routes/user/page.data.ts` file, you can export a Data Loader function:
53
29
 
54
30
  ```ts title="routes/user/page.data.ts"
55
31
  export type ProfileData = {
@@ -62,52 +38,69 @@ export const loader = async (): Promise<ProfileData> => {
62
38
  };
63
39
  ```
64
40
 
65
- :::caution
66
- Here, routing components and `data` files share a type, so the `import type` syntax should be used.
41
+ :::warning Compatibility
42
+ - In previous versions, Data Loader was defined in a `.loader` file. In the current version, we recommend defining it in a `.data` file, while maintaining compatibility with `.loader` files.
43
+ - In `.loader` files, the Data Loader can be exported as default. In `.data` files, it should be named `loader` export.
44
+ ```ts
45
+ // xxx.loader.ts
46
+ export default () => {}
67
47
 
48
+ // xxx.data.ts
49
+ export const loader = () => {}
50
+ ```
68
51
  :::
69
52
 
70
- In the CSR environment, the `loader` function is executed on the client and can use browser APIs (although it is not necessary and not recommended).
53
+ In the route component, you can use the `useLoaderData` function to fetch data:
54
+
55
+ ```ts title="routes/user/page.tsx"
56
+ import { useLoaderData } from '@modern-js/runtime/router';
57
+ import type { ProfileData } from './page.data.ts';
58
+
59
+ export default function UserPage() {
60
+ const profileData = useLoaderData() as ProfileData;
61
+ return <div>{profileData}</div>;
62
+ }
63
+ ```
64
+
65
+ :::caution
66
+ Route components and `.data` files share types. Use `import type` to avoid unexpected side effects.
67
+ :::
71
68
 
72
- In the SSR environment, whether it is the first screen or client navigation, the `loader` function will only be executed on the server, and any Node.js API can be called here. Also, any dependencies and code used here will not be included in the client's bundle.
69
+ In a CSR environment, the `loader` function executes on the browser side and can use browser APIs (though it's usually unnecessary and not recommended).
73
70
 
74
- :::info
75
- In future versions, Modern.js may support running the `loader` function on the server in the CSR environment to improve performance and security. Therefore, it is recommended to ensure that the `loader` function is as pure as possible and only used for data fetching scenarios.
71
+ In an SSR environment, the `loader` function only executes on the server side for initial page loads and when navigating. Here it can call any Node.js APIs, and any dependencies or code used won't be included in the client-side bundle.
76
72
 
73
+ :::tip
74
+ In future versions, Modern.js may support running `loader` functions on the server side even in CSR environments to improve performance and security. Therefore, it is advisable to keep the `loader` function pure, handling only data fetching scenarios.
77
75
  :::
78
76
 
79
- When navigating on the client based on Modern.js's [conventional routing](/guides/basic-features/routes), all `loader` functions will be executed in parallel (requested). That is, when accessing `/user/profile`, the loader functions under `/user` and `/user/profile` will be executed in parallel (requested) to improve the performance of the client.
77
+ When navigating on the client side, based on [conventional routing](/guides/basic-features/routes), Modern.js supports parallel execution (requests) of all `loader` functions. For example, when visiting `/user/profile`, the `loader` functions under `/user` and `/user/profile` will execute in parallel, solving the request-render waterfall issue and significantly improving page performance.
80
78
 
81
- ### The `loader` Function
79
+ ## `loader` Function
82
80
 
83
- The `loader` function has two input parameters:
81
+ The `loader` function has two parameters used for getting route parameters and request information.
84
82
 
85
- #### `params`
83
+ ### params
86
84
 
87
- When the route file is accessed through `[]`, it is used as [dynamic routing](/guides/basic-features/routes#dynamic-routing), and the dynamic routing fragment is passed as a parameter to the `loader` function:
85
+ `params` is the dynamic route segments when the route is a [dynamic route](/guides/basic-features/routes#dynamic-routes), which passed as parameters to the `loader` function:
88
86
 
89
- ```tsx
90
- // routes/user/[id]/page.data.tsx
87
+ ```tsx title="routes/user/[id]/page.data.ts"
91
88
  import { LoaderFunctionArgs } from '@modern-js/runtime/router';
92
89
 
93
- export default async ({ params }: LoaderFunctionArgs) => {
90
+ // When visiting /user/123, the function parameter is `{ params: { id: '123' } }`
91
+ export const loader = async ({ params }: LoaderFunctionArgs) => {
94
92
  const { id } = params;
95
93
  const res = await fetch(`https://api/user/${id}`);
96
94
  return res.json();
97
95
  };
98
96
  ```
99
97
 
100
- When accessing `/user/123`, the parameter of the `loader` function is `{ params: { id: '123' } }`.
101
-
102
- #### `request`
98
+ ### request
103
99
 
104
- `request` is a [Fetch Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) instance.
105
-
106
- A common usage scenario is to get query parameters through `request`:
100
+ `request` is an instance of [Fetch Request](https://developer.mozilla.org/en-US/docs/Web/API/Request). A common use case is to get query parameters from `request`:
107
101
 
108
102
  ```tsx
109
- // routes/user/[id]/page.data.ts
110
- import { LoaderFunctionArgs } from '@modern-js/runtime/router';
103
+ import { LoaderFunctionArgs } from '@modern-js/runtime/router;
111
104
 
112
105
  export const loader = async ({ request }: LoaderFunctionArgs) => {
113
106
  const url = new URL(request.url);
@@ -116,9 +109,9 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
116
109
  };
117
110
  ```
118
111
 
119
- #### Return Value
112
+ ### Return Value
120
113
 
121
- The return value of the `loader` function can be any serializable content or a [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) instance:
114
+ The return value of the `loader` function **must be one of two data structures**: a serializable data object or an instance of [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
122
115
 
123
116
  ```tsx
124
117
  const loader = async (): Promise<ProfileData> => {
@@ -129,7 +122,7 @@ const loader = async (): Promise<ProfileData> => {
129
122
  export default loader;
130
123
  ```
131
124
 
132
- By default, the `Content-type` of the response returned by the `loader` is `application/json`, and the `status` is 200. You can customize the `Response` to set it:
125
+ By default, the `loader` response's `Content-type` is `application/json`, and its `status` is 200. You can customize the `Response` to change these:
133
126
 
134
127
  ```tsx
135
128
  const loader = async (): Promise<ProfileData> => {
@@ -143,25 +136,41 @@ const loader = async (): Promise<ProfileData> => {
143
136
  };
144
137
  ```
145
138
 
146
- ### Request API
139
+ ## Using Data Loader in Different Environments
140
+
141
+ The `loader` function may run on the server or client. When it runs on the server, it's called a Server Loader; when it runs on the client, it's called a Client Loader.
142
+
143
+ In CSR applications, the `loader` function runs on the client, hence it is a Client Loader by default.
144
+
145
+ In SSR applications, the `loader` function runs only on the server, hence it is a Server Loader by default. During SSR rendering, Modern.js will directly call the `loader` function on the server side. When navigating on the client side, Modern.js sends an HTTP request to the SSR service, also triggering the `loader` function on the server side.
146
+
147
+ :::note
148
+ Having the `loader` function run only on the server in SSR applications brings several benefits:
149
+ - **Simplifies usage**: Guarantees consistent data-fetching methods in SSR applications, so developers don't have to distinguish between client and server code.
150
+ - **Reduces client bundle size**: Moves logic code and dependencies from the client to the server.
151
+ - **Improves maintainability**: Less direct influence of data logic on front-end UI and avoids issues of accidentally including server dependencies in the client bundle or vice versa.
152
+ :::
147
153
 
148
- Modern.js provides a polyfill for the `fetch` API to make requests. This API is consistent with the browser's `fetch` API, but can also be used to make requests on the server. This means that whether it is CSR or SSR, a unified `fetch` API can be used to get data:
154
+ We recommend using the `fetch` API in `loader` functions to make requests. Modern.js provides a default polyfill for the `fetch` API, allowing it to be used on the server. This means you can fetch data in a consistent manner whether in CSR or SSR:
149
155
 
150
156
  ```tsx
151
- function loader() {
152
- const res = await fetch('https://api/user/profile');
157
+ export async function loader() {
158
+ const res = await fetch('URL_ADDRESS');
159
+ return {
160
+ message: res.message
161
+ }
153
162
  }
154
163
  ```
155
164
 
156
- ### Error Handling
165
+ ## Error Handling
157
166
 
158
- #### Basic Usage
167
+ ### Basic Usage
159
168
 
160
- In the `loader` function, errors can be handled by throwing an `error` or a `response`. When an error is thrown in the `loader` function, Modern.js will stop executing the code in the current `loader` and switch the front-end UI to the defined [`ErrorBoundary`](/guides/basic-features/routes#error-handling) component:
169
+ In a `loader` function, you can handle errors by using `throw error` or `throw response`. When an error is thrown in the `loader` function, Modern.js will stop executing the remaining code in the current `loader` and switch the front-end UI to the defined [`ErrorBoundary`](/guides/basic-features/routes#error-handling) component:
161
170
 
162
171
  ```tsx
163
- // routes/user/profile/page.data.tsx
164
- export const loader = async function loader() {
172
+ // routes/user/profile/page.data.ts
173
+ export async function loader() {
165
174
  const res = await fetch('https://api/user/profile');
166
175
  if (!res.ok) {
167
176
  throw res;
@@ -184,11 +193,11 @@ const ErrorBoundary = () => {
184
193
  export default ErrorBoundary;
185
194
  ```
186
195
 
187
- #### Practice
196
+ ### Modify HTTP Code
188
197
 
189
- In an SSR project you can control the status code of a page and display the corresponding UI by `throw response` in the data loader, as in the following example, where there is one loader for the entire routing route
198
+ In SSR projects, you can control the page status code by throwing a response in the `loader` function and display the corresponding UI.
190
199
 
191
- For example, if there is a loader in the entire routing route that throws a response, the status code of the page will be consistent with this `response` and the UI of the page will switch to `ErrorBoundary`.
200
+ In the following example, the page's status code will match this `response`, and the page will display the `ErrorBoundary` UI:
192
201
 
193
202
  ```ts
194
203
  // routes/user/profile/page.data.ts
@@ -201,7 +210,7 @@ export async function loader() {
201
210
  }
202
211
 
203
212
  // routes/error.tsx
204
- import { useRouteError } from '@modern-js/runtime/router';
213
+ import { useRouteError } from '@modern-js/runtime/router;
205
214
  const ErrorBoundary = () => {
206
215
  const error = useRouteError() as { data: string };
207
216
  return <div className="error">{error.data}</div>;
@@ -210,16 +219,16 @@ const ErrorBoundary = () => {
210
219
  export default ErrorBoundary;
211
220
  ```
212
221
 
213
- ### Get data from parent component
222
+ ## Accessing Data from Upper Components
214
223
 
215
- In many cases, child components need to access data in the parent component `loader`. You can easily get the data from the parent component using `useRouteLoaderData`:
224
+ In many scenarios, child components need to access data from the upper component's `loader`. You can use the `useRouteLoaderData` function to easily get data from the upper component:
216
225
 
217
226
  ```tsx
218
227
  // routes/user/profile/page.tsx
219
228
  import { useRouteLoaderData } from '@modern-js/runtime/router';
220
229
 
221
- export default function UserLayout() {
222
- // Get the data returned by the loader in routes/user/layout.data.ts
230
+ export function UserLayout() {
231
+ // Get data returned by the `loader` in routes/user/layout.data.ts
223
232
  const data = useRouteLoaderData('user/layout');
224
233
  return (
225
234
  <div>
@@ -230,9 +239,9 @@ export default function UserLayout() {
230
239
  }
231
240
  ```
232
241
 
233
- The `useRouteLoaderData` function accepts a parameter `routeId`. When using [conventional routing](/guides/basic-features/routes), Modern.js will automatically generate the `routeId` for you. The value of `routeId` is the path of the corresponding component relative to `src/routes`. For example, in the above example, if the child component wants to get the data returned by the loader in `routes/user/layout.tsx`, the value of `routeId` is `user/layout`.
242
+ `useRouteLoaderData` accepts a parameter `routeId`. In conventional routing, Modern.js automatically generates the `routeId`, which is the path of the corresponding component relative to `src/routes`. In the example above, the `routeId` for fetching data from `routes/user/layout.tsx`'s loader is `user/layout`.
234
243
 
235
- In a multi-entry (MPA) scenario, the value of `routeId` needs to include the name of the corresponding entry. Unless specified, the entry name is generally the name of the entry directory. For example, in the following directory structure:
244
+ In a multi-entry scenario, the `routeId` value needs to include the corresponding entry name, which is typically the directory name if not explicitly specified. For example, with the following directory structure:
236
245
 
237
246
  ```bash
238
247
  .
@@ -245,12 +254,12 @@ In a multi-entry (MPA) scenario, the value of `routeId` needs to include the nam
245
254
  └── layout.tsx
246
255
  ```
247
256
 
248
- If you want to get the data returned by the `loader` in `entry1/routes/layout.tsx`, the value of `routeId` is `entry1_layout`.
257
+ To get data returned by the loader in `entry1/routes/layout.tsx`, the `routeId` value would be `entry1_layout`.
249
258
 
250
- ### Loading UI (Experimental)
259
+ ## Loading UI (Experimental)
251
260
 
252
- :::info
253
- This feature is currently experimental and the API may change in the future.
261
+ :::info Experimental
262
+ This feature is currently experimental, and its API may change in the future.
254
263
  :::
255
264
 
256
265
  Create `user/layout.data.ts` and add the following code:
@@ -269,76 +278,62 @@ export const loader = () =>
269
278
  }, 1000);
270
279
  }),
271
280
  });
272
-
273
281
  ```
274
282
 
275
283
  Add the following code in `user/layout.tsx`:
276
284
 
277
285
  ```tsx title="routes/user/layout.tsx"
278
- import {
279
- Await,
280
- defer,
281
- useLoaderData,
282
- Outlet
283
- } from '@modern-js/runtime/router';
286
+ import { Await, defer, useLoaderData, Outlet } from '@modern-js/runtime/router';
284
287
 
285
288
  export default function UserLayout() {
286
- const { userInfo } = useLoaderData() as {userInfo: Promise<UserInfo>};
289
+ const { userInfo } = useLoaderData() as { userInfo: Promise<UserInfo> };
287
290
  return (
288
291
  <div>
289
- <React.Suspense
290
- fallback={<p>Loading...</p>}
291
- >
292
- <Await resolve={userInfo} children={userInfo => (
293
- <div>
294
- <span>{userInfo.name}</span>
295
- <span>{userInfo.age}</span>
296
- <Outlet/>
297
- </div>
298
- )}>
299
- </Await>
292
+ <React.Suspense fallback={<p>Loading...</p>}>
293
+ <Await
294
+ resolve={userInfo}
295
+ children={userInfo => (
296
+ <div>
297
+ <span>{userInfo.name}</span>
298
+ <span>{userInfo.age}</span>
299
+ <Outlet />
300
+ </div>
301
+ )}
302
+ ></Await>
300
303
  </React.Suspense>
301
304
  </div>
302
305
  );
303
306
  }
304
307
  ```
305
308
 
306
- :::info
307
- For details on how to use the Await component, please refer to [Await](https://reactrouter.com/en/main/components/await).
308
-
309
- For details on how to use defer, please refer to [defer](https://reactrouter.com/en/main/guides/deferred).
309
+ :::tip
310
+ For more details on `<Await>`, refer to the [Await](https://reactrouter.com/en/main/components/await) documentation. For more details on `defer`, refer to the [defer](https://reactrouter.com/en/main/guides/deferred) documentation.
310
311
  :::
311
312
 
312
- ### Data Cache
313
+ ## Data Caching
313
314
 
314
- In routing navigation, Modern.js will only load the data of the changed part of the route.
315
- For example, the current route is `a/b`, and the Data Loader corresponding to the `a` path has been executed.
316
- When jumping from `/a/b` to `/a/c`, the Data Loader corresponding to `a` path will not be re-executed,
317
- and the Data Loader corresponding to `c` path will execute and fetch the data.
315
+ During route navigation, Modern.js will only load data for the parts of the route that change. For example, if the current route is `a/b`, and the Data Loader for the `a` path has already executed, then when transitioning from `/a/b` to `/a/c`, the Data Loader for the `a` path will not re-execute, but the Data Loader for the `c` path will execute and fetch the data.
318
316
 
319
- It is mean that Modern.js will only load the data for the routing change portion of the data load,
320
- and this default optimization strategy avoids invalid duplicate data requests.
317
+ This default optimization strategy avoids redundant data requests. However, you might wonder how to update the data for the `a` path's Data Loader?
321
318
 
322
- You may ask, how to update the data of the `a` path corresponding to the Data Loader?
319
+ In Modern.js, the Data Loader for a specific path will reload in the following scenarios:
323
320
 
324
- In Modern.js, Modern.js will reload the data of the corresponding routing path in the following cases:
321
+ 1. After triggering a [Data Action](/guides/basic-features/data/data-write.md)
322
+ 2. When URL parameters change
323
+ 3. When the user clicks a link that matches the current page URL
324
+ 4. When the route component defines a [`shouldRevalidate`](#/shouldrevalidate) function that returns `true`
325
325
 
326
- 1. After [Data Action](/guides/basic-features/data/data-write.md) is triggered
327
- 2. The search params on the url have changed.
328
- 3. The link clicked by the user is the same as the URL of the current page.
329
- 4. The [`shouldRevalidate`](#/shouldrevalidate) function is defined in the routing component, which returns true
330
-
331
- :::info
332
- If you define the [`shouldRevalidate`](#/shouldrevalidate) function on the route, the function will be checked first to determine whether the data needs to be reloaded.
326
+ :::tip
327
+ If you define a [`shouldRevalidate`](#/shouldrevalidate) function for a route, this function will be checked first to determine whether data reloads.
333
328
  :::
334
329
 
335
330
  ### `shouldRevalidate`
336
331
 
337
332
  :::warning
338
- Currently `shouldRevalidate` works under csr and streaming ssr.
333
+ Currently, `shouldRevalidate` only takes effect in CSR and Streaming SSR.
339
334
  :::
340
335
 
341
- In each routing component (`layout.tsx`, `page.tsx`, `$.tsx`), we can export a `shouldRevalidate` function, which is triggered each time a route changes in the project. This function controls which routes' data are reloaded, and when it returns true, the data for the corresponding route is reloaded. data of the corresponding route will be reloaded.
336
+ In route components (`layout.tsx`, `page.tsx`, `$.tsx`), you can export a `shouldRevalidate` function. This function is triggered on each route change in the project and can control which route data to reload. If this function returns `true`, Modern.js will reload the corresponding route data.
342
337
 
343
338
  ```ts title="routes/user/layout.tsx"
344
339
  import type { ShouldRevalidateFunction } from '@modern-js/runtime/router';
@@ -358,65 +353,31 @@ export const shouldRevalidate: ShouldRevalidateFunction = ({
358
353
  };
359
354
  ```
360
355
 
361
- :::info
362
- For more details about the `shouldRevalidate` function, please refer to [react-router](https://reactrouter.com/en/main/route/should-revalidate)
363
- :::
364
-
365
- ### Client Loader
366
-
367
- :::info
368
- 1. This feature requires version x.36.0 or above, and it‘s recommended to use the latest version of the framework.
369
- 2. Only SSR projects have Client Loaders, while in CSR projects, it can be considered as the default Client Loader.
370
- 3. This feature can be used progressively and not every project needs it. For specific information, please refer to the explanation of applicable scenarios in the document below.
371
-
372
- :::
373
-
374
- #### Applicable scenarios
375
-
376
- In the SSR project, the code in Data Loader will only be executed on the server side when the client performs SPA navigation.
377
- The framework will send an HTTP request to the SSR service to trigger the execution of Data Loader.
378
- However, in some scenarios, we may expect that requests sent by clients do not go through the SSR service and directly request data sources.
379
-
380
- :::info
381
- Why the Data Loader is only executed server-side in SSR projects can be found in [FAQ](#faq)
382
-
356
+ :::tip
357
+ For more details on the `shouldRevalidate` function, refer to the [react-router](https://reactrouter.com/en/main/route/should-revalidate) documentation.
383
358
  :::
384
359
 
385
- For example, the following scenarios:
386
-
387
- 1. During SSR degradation, it is not desired for the framework to send requests to the SSR service to obtain data. Instead, direct requests to the data source are preferred.
388
- 2. There is some cache on the client side, and we don't want to request SSR service to fetch data.
389
-
390
- In these scenarios, we can use Client Loader. After adding the Client Loader, in the following scenarios, the code in the Client Loader will be called instead of sending requests to SSR services:
391
-
392
- 1. After SSR is downgraded to CSR, when fetch data on the client side, Client Loader will be executed instead of the framework sending requests to Data Loader (Server) to fetch data.
393
- 2. When performing SPA navigation in SSR projects and fetch data, Client Loader will be executed.
360
+ ## Incorrect Usages
394
361
 
395
-
396
- ### Incorrect usage
397
-
398
- 1. The `loader` can only return serializable data. In the SSR environment, the return value of the `loader` function will be serialized as a JSON string and then deserialized into an object on the client side. Therefore, the `loader` function cannot return non-serializable data (such as functions).
362
+ 1. The `loader` can only return serializable data. In an SSR environment, the return value of the `loader` function will be serialized as a JSON string and then deserialized as an object on the client side. Therefore, the `loader` function should not return non-serializable data such as functions.
399
363
 
400
364
  :::warning
401
- Currently, there is no such restriction under CSR, but we strongly recommend that you follow this restriction, and we may also add this restriction under CSR in the future.
365
+ This limitation currently does not exist in CSR, but we strongly recommend adhering to it, as future versions may enforce this restriction in CSR as well.
402
366
  :::
403
367
 
404
368
  ```ts
405
369
  // This won't work!
406
- export const loader = async () => {
407
- const res = fetch('https://api/user/profile');
408
- return res.json();
370
+ export default () => {
371
+ return {
372
+ user: {},
373
+ method: () => {},
374
+ };
409
375
  };
410
-
411
- import { loader } from './page.data.ts';
412
- export default function RouteComp() {
413
- const data = loader();
414
- }
415
376
  ```
416
377
 
417
- 2. Modern.js will call the `loader` function for you, so you should not call the `loader` function yourself:
378
+ 2. Modern.js will call the `loader` function for you, and you should not call it yourself:
418
379
 
419
- ```tsx
380
+ ```ts
420
381
  // This won't work!
421
382
  export const loader = async () => {
422
383
  const res = fetch('https://api/user/profile');
@@ -429,7 +390,7 @@ export default function RouteComp() {
429
390
  }
430
391
  ```
431
392
 
432
- 3. You should not import the loader file from the route component, and you should also avoid importing variables from the route component into the loader file. If you need to share types, you should use `import type`.
393
+ 3. Do not import `loader` files from route components, and do not import variables from route components into `loader` files. If you need to share types, use `import type`.
433
394
 
434
395
  ```ts
435
396
  // Not allowed
@@ -445,85 +406,23 @@ export default function UserPage() {
445
406
  }
446
407
 
447
408
  // routes/layout.data.ts
448
- import { fetch } from './layout.tsx'; // should not be imported from the routing component
409
+ import { fetch } from './layout.tsx'; // should not be imported from the route component
449
410
  export type ProfileData = {
450
411
  /* some types */
451
412
  };
452
413
 
453
- export default async (): Promise<ProfileData> => {
414
+ export const loader = async (): Promise<ProfileData> => {
454
415
  const res = await fetch('https://api/user/profile');
455
416
  return await res.json();
456
417
  };
457
418
  ```
458
419
 
459
- 4. When running on the server, the `loader` function will be bundled into a unified bundle, so we do not recommend using `__filename` and `__dirname` in server-side code.
460
-
461
- ### FAQ
462
-
463
- 1. Relationship between `loader` and BFF functions
420
+ 4. When running on the server, `loader` functions are packaged into a single bundle. Therefore, we do not recommend using `__filename` and `__dirname` in server code.
464
421
 
465
- In CSR projects, `loader` is executed on the client side, and the BFF function can be called directly in the `loader` to make interface requests.
422
+ ## Frequently Asked Questions
466
423
 
467
- In SSR projects, each `loader` is also a server-side interface. We recommend using the `loader` instead of the BFF function with an http method of `get` as the interface layer to avoid an extra layer of forwarding and execution.
424
+ 1. What is the relationship between `loader` and BFF functions?
468
425
 
469
- 2. Why is the Data Loader only executed on the server-side in SSR projects?
426
+ In CSR projects, the `loader` executes on the client side and can directly call BFF functions to make API requests.
470
427
 
471
- The Data Loader in our SSR project is designed to only run on the server side. The main reasons for sending requests from the client to the server during client-side rendering are as follows:
472
-
473
- - **Simplified usage**, when using a server loader, the data fetching code for both the SSR and CSR phases is in the server loader (the real calls are made by the framework layer), and the code in the server loader doesn't need to care whether it's in a browser environment or a server-side environment.
474
- - **Reducing data for network requests**, The server loader can be used as a BFF layer, which reduces the amount of data that needs to be fetched by the front-end at runtime.
475
- - **Reduce client-side bundle size**, moving the logic code and its dependencies from the client to the server.
476
- - **Improve maintainability**, moving the logic code to the server side reduces the direct impact of data logic on the front-end UI. In addition, the problem of mistakenly introducing server-side dependencies in the client-side bundle or client-side dependencies in the server-side bundle is also avoided.
477
-
478
-
479
- ## useLoader (old version)
480
-
481
- **`useLoader`** is a legacy API in Modern.js v1. This API is a React Hook designed specifically for SSR applications, allowing developers to fetch data in components in isomorphic development.
482
-
483
- :::tip
484
- It is not necessary to use `useLoader` to fetch data in CSR projects, and `useLoader` is not supported when using Rspack as the bundler.
485
- :::
486
-
487
- Here is the simplest example:
488
-
489
- ```tsx
490
- import { useLoader } from '@modern-js/runtime';
491
-
492
- export default () => {
493
- const { data } = useLoader(async () => {
494
- console.log('fetch in useLoader');
495
-
496
- // No real request is sent here, just a hard coding data is returned.
497
- // In a real project, the data obtained from the remote end should be returned.
498
- return {
499
- name: 'Modern.js',
500
- };
501
- });
502
-
503
- return <div>Hello, {data?.name}</div>;
504
- };
505
- ```
506
-
507
- After running the above code, when you access the page, you can see that logs are output to the terminal, but not printed in the browser console.
508
-
509
- This is because Modern.js collects the data returned by `useLoader` during server-side rendering and injects it into the corresponding HTML. If the SSR rendering is successful, you can see the following code snippet in the HTML:
510
-
511
- ```html
512
- <script>
513
- window._SSR_DATA = {};
514
- </script>
515
- ```
516
-
517
- This global variable is used to record data, and during the browser-side rendering process, this data is used first. If the data does not exist, the `useLoader` function will be executed again.
518
-
519
- :::note
520
- During the build phase, Modern.js will automatically generate a Loader ID for each `useLoader` and inject it into the SSR and CSR JS Bundles to associate the Loader with the data.
521
- :::
522
-
523
- Compared to `getServerSideProps` in Next.js, which fetches data before rendering, using `useLoader` allows you to get data required for local UI in the component without passing data through multiple layers. Similarly, you don't have to add redundant logic to the outermost data acquisition function because different routes require different data requests. Of course, `useLoader` also has some issues, such as difficulties in server-side code tree shaking and the need for an additional pre-rendering step on the server.
524
-
525
- In the new version of Modern.js, a new Loader solution has been designed. The new solution solves these problems and can be optimized for page performance in conjunction with [conventional routing](/guides/basic-features/routes).
526
-
527
- :::note
528
- For detailed API information, see [useLoader](/apis/app/runtime/core/use-loader).
529
- :::
428
+ In SSR projects, each `loader` is also a server-side API. We recommend using `loader` instead of BFF functions with an HTTP method of `get` to avoid an extra layer of forwarding and execution.