@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
@@ -0,0 +1,230 @@
1
+ # Streaming SSR
2
+
3
+ Streaming SSR is a new rendering method that updates the page content in real-time as users interact with it, enhancing user experience.
4
+
5
+ In conventional rendering, the page is rendered all at once. In streaming rendering, the page is rendered progressively, loading data step-by-step as users interact with the page instead of loading all data at once.
6
+
7
+ Compared to traditional rendering:
8
+
9
+ - **Faster Perceived Speed**: Streaming rendering can progressively display content, quickly rendering the home page.
10
+ - **Enhanced User Experience**: Users can see page content faster and interact without waiting for the entire page to render.
11
+ - **Better Performance Control**: Developers can better control the loading priority and order, optimizing performance and user experience.
12
+ - **Better Adaptability**: Streaming rendering adapts better to various network speeds and device performance, ensuring good performance across different environments.
13
+
14
+ ## Enabling Streaming Rendering
15
+
16
+ Modern.js supports React 18's streaming rendering, which can be enabled as follows:
17
+
18
+ ```ts title="modern.config.ts"
19
+ import { defineConfig } from '@modern-js/app-tools';
20
+
21
+ export default defineConfig({
22
+ server: {
23
+ ssr: {
24
+ mode: 'stream',
25
+ },
26
+ },
27
+ });
28
+ ```
29
+
30
+ Modern.js streaming rendering is based on React Router and involves several key APIs:
31
+
32
+ - [`defer`](https://reactrouter.com/en/main/utils/defer): Used in Data Loader to support asynchronous data fetching.
33
+ - [`Await`](https://reactrouter.com/en/main/components/await): Used to render the asynchronous data returned by the Data Loader.
34
+ - [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value): Used to fetch data from the nearest parent `Await` component.
35
+
36
+ ## Fetching Data
37
+
38
+ ```ts title="user/[id]/page.data.ts"
39
+ import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
40
+
41
+ interface User {
42
+ name: string;
43
+ age: number;
44
+ }
45
+
46
+ export interface Data {
47
+ data: User;
48
+ }
49
+
50
+ export const loader = ({ params }: LoaderFunctionArgs) => {
51
+ const userId = params.id;
52
+
53
+ const user = new Promise<User>(resolve => {
54
+ setTimeout(() => {
55
+ resolve({
56
+ name: `user-${userId}`,
57
+ age: 18,
58
+ });
59
+ }, 200);
60
+ });
61
+
62
+ return defer({ data: user });
63
+ };
64
+ ```
65
+
66
+ Here, `user` is a Promise object representing asynchronously fetched data, processed using `defer`. Notice that `defer` must receive an object parameter; a direct Promise cannot be passed.
67
+
68
+ Additionally, `defer` can receive both asynchronous and synchronous data. In the example below, short-duration requests are returned using object data, while longer-duration requests are returned using a Promise:
69
+
70
+ ```ts title="user/[id]/page.data.ts"
71
+ export const loader = ({ params }: LoaderFunctionArgs) => {
72
+ const userId = params.id;
73
+
74
+ const user = new Promise<User>(resolve => {
75
+ setTimeout(() => {
76
+ resolve({
77
+ name: `user-${userId}`,
78
+ age: 18,
79
+ });
80
+ }, 2000);
81
+ });
82
+
83
+ const otherData = new Promise<string>(resolve => {
84
+ setTimeout(() => {
85
+ resolve('some sync data');
86
+ }, 200);
87
+ });
88
+
89
+ return defer({
90
+ data: user,
91
+ other: await otherData,
92
+ });
93
+ };
94
+ ```
95
+
96
+ This way, the application can prioritize displaying partially available content without waiting for the most time-consuming data requests.
97
+
98
+ ## Rendering Data
99
+
100
+ To render the asynchronous data returned by the Data Loader, use the `Await` component. For example:
101
+
102
+ ```tsx title="user/[id]/page.tsx"
103
+ import { Await, useLoaderData } from '@modern-js/runtime/router';
104
+ import { Suspense } from 'react';
105
+ import type { Data } from './page.data';
106
+
107
+ const Page = () => {
108
+ const data = useLoaderData() as Data;
109
+
110
+ return (
111
+ <div>
112
+ User info:
113
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
114
+ <Await resolve={data.data}>
115
+ {user => {
116
+ return (
117
+ <div id="data">
118
+ name: {user.name}, age: {user.age}
119
+ </div>
120
+ );
121
+ }}
122
+ </Await>
123
+ </Suspense>
124
+ </div>
125
+ );
126
+ };
127
+
128
+ export default Page;
129
+ ```
130
+
131
+ The `Await` component needs to be wrapped inside a `Suspense` component. The `resolve` prop of `Await` should be the asynchronously fetched data from the Data Loader. When the data is fetched, it will be rendered using the [Render Props](https://zh-hans.react.dev/reference/react/cloneElement#passing-data-with-a-render-prop) pattern. During data fetching, the content set by the `fallback` prop of `Suspense` is displayed.
132
+
133
+ :::warning Warning
134
+ When importing types from the `page.data.ts` file, use `import type` to ensure only type information is imported, preventing Data Loader code from being bundled into the frontend.
135
+ :::
136
+
137
+ In the component, you can also fetch asynchronous data returned by the Data Loader using `useAsyncValue`. For example:
138
+
139
+ ```tsx title='page.tsx'
140
+ import { useAsyncValue } from '@modern-js/runtime/router';
141
+
142
+ const UserInfo = () => {
143
+ const user = useAsyncValue();
144
+ return (
145
+ <div>
146
+ name: {user.name}, age: {user.age}
147
+ </div>
148
+ );
149
+ };
150
+
151
+ const Page = () => {
152
+ const data = useLoaderData() as Data;
153
+ return (
154
+ <div>
155
+ User info:
156
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
157
+ <Await resolve={data.data}>
158
+ <UserInfo />
159
+ </Await>
160
+ </Suspense>
161
+ </div>
162
+ );
163
+ };
164
+
165
+ export default Page;
166
+ ```
167
+
168
+ ## Error Handling
169
+
170
+ The `errorElement` prop of the `Await` component handles errors in Data Loader or sub-component rendering. For example, intentionally throwing an error in the Data Loader function:
171
+
172
+ ```ts title="page.loader.ts"
173
+ import { defer } from '@modern-js/runtime/router';
174
+
175
+ export default () => {
176
+ const data = new Promise((resolve, reject) => {
177
+ setTimeout(() => {
178
+ reject(new Error('error occurs'));
179
+ }, 200);
180
+ });
181
+
182
+ return defer({ data });
183
+ };
184
+ ```
185
+
186
+ Then, fetch the error using `useAsyncError` and set a component to render the error message for the `errorElement` prop of the `Await` component:
187
+
188
+ ```tsx title="page.ts"
189
+ import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
190
+ import { Suspense } from 'react';
191
+
192
+ export default function Page() {
193
+ const data = useLoaderData();
194
+
195
+ return (
196
+ <div>
197
+ Error page
198
+ <Suspense fallback={<div>loading ...</div>}>
199
+ <Await resolve={data.data} errorElement={<ErrorElement />}>
200
+ {(data: any) => {
201
+ return <div>never displayed</div>;
202
+ }}
203
+ </Await>
204
+ </Suspense>
205
+ </div>
206
+ );
207
+ }
208
+
209
+ function ErrorElement() {
210
+ const error = useAsyncError() as Error;
211
+ return <p>Something went wrong! {error.message}</p>;
212
+ }
213
+ ```
214
+
215
+ ## Waiting for All Content to Load for Crawlers
216
+
217
+ Streaming can enhance user experience by allowing users to perceive content as it becomes available.
218
+
219
+ However, when a crawler visits the page, it might need to load all content and output the entire HTML at once, rather than progressively loading it.
220
+
221
+ Modern.js uses [isbot](https://www.npmjs.com/package/isbot) to determine if a request is from a crawler based on the `user-agent` header.
222
+
223
+ import StreamSSRPerformance from '@site-docs-en/components/stream-ssr-performance';
224
+
225
+ <StreamSSRPerformance />
226
+
227
+ ## Related Documentation
228
+
229
+ 1. [Deferred Data](https://reactrouter.com/en/main/guides/deferred)
230
+ 2. [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37)