@modern-js/main-doc 2.58.2 → 2.59.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. package/docs/en/apis/app/runtime/core/use-loader.mdx +1 -1
  2. package/docs/en/community/blog/_meta.json +1 -6
  3. package/docs/en/components/deploy.mdx +1 -1
  4. package/docs/en/components/init-app.mdx +0 -1
  5. package/docs/en/components/init-rspack-app.mdx +0 -1
  6. package/docs/en/components/ssr-monitor.mdx +3 -0
  7. package/docs/en/configure/_meta.json +1 -1
  8. package/docs/en/configure/app/output/ssg.mdx +52 -141
  9. package/docs/en/configure/app/tools/swc.mdx +1 -1
  10. package/docs/en/configure/app/tools/tailwindcss.mdx +1 -1
  11. package/docs/en/guides/advanced-features/_meta.json +0 -8
  12. package/docs/en/guides/advanced-features/bff/_meta.json +1 -6
  13. package/docs/en/guides/advanced-features/rsbuild-plugin.mdx +2 -2
  14. package/docs/en/guides/advanced-features/rspack-start.mdx +7 -22
  15. package/docs/en/guides/basic-features/_meta.json +31 -9
  16. package/docs/en/guides/basic-features/css/_meta.json +1 -0
  17. package/docs/en/guides/basic-features/css/css-in-js.mdx +34 -0
  18. package/docs/en/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -4
  19. package/docs/en/guides/basic-features/css/css.mdx +25 -0
  20. package/docs/en/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +5 -66
  21. package/docs/en/guides/basic-features/data/_meta.json +1 -4
  22. package/docs/en/guides/basic-features/data/data-fetch.mdx +134 -235
  23. package/docs/en/guides/basic-features/data/data-write.mdx +66 -77
  24. package/docs/en/guides/basic-features/debug/_meta.json +1 -0
  25. package/docs/en/guides/basic-features/debug/rsdoctor.mdx +57 -0
  26. package/docs/en/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +2 -0
  27. package/docs/en/guides/basic-features/render/_meta.json +1 -0
  28. package/docs/en/guides/basic-features/render/ssg.mdx +208 -0
  29. package/docs/en/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +38 -50
  30. package/docs/en/guides/basic-features/render/ssr.mdx +301 -0
  31. package/docs/en/guides/basic-features/render/streaming-ssr.mdx +230 -0
  32. package/docs/en/guides/basic-features/routes.mdx +275 -263
  33. package/docs/en/guides/basic-features/static-assets/_meta.json +1 -0
  34. package/docs/en/guides/basic-features/static-assets.mdx +1 -1
  35. package/docs/en/guides/basic-features/testing/_meta.json +1 -0
  36. package/docs/en/guides/basic-features/testing/cypress.mdx +95 -0
  37. package/docs/en/guides/basic-features/testing/jest.mdx +148 -0
  38. package/docs/en/guides/basic-features/testing/playwright.mdx +111 -0
  39. package/docs/en/guides/basic-features/testing/vitest.mdx +100 -0
  40. package/docs/en/guides/concept/_meta.json +1 -4
  41. package/docs/en/guides/concept/entries.mdx +78 -47
  42. package/docs/en/guides/get-started/_meta.json +1 -7
  43. package/docs/en/guides/get-started/introduction.mdx +1 -1
  44. package/docs/en/guides/get-started/quick-start.mdx +1 -2
  45. package/docs/en/guides/get-started/tech-stack.mdx +4 -6
  46. package/docs/en/guides/get-started/upgrade.mdx +16 -2
  47. package/docs/en/guides/topic-detail/framework-plugin/_meta.json +1 -1
  48. package/docs/en/guides/topic-detail/generator/_meta.json +1 -1
  49. package/docs/en/guides/topic-detail/generator/create/_meta.json +1 -5
  50. package/docs/en/guides/topic-detail/generator/create/config.mdx +0 -10
  51. package/docs/en/guides/topic-detail/generator/create/use.mdx +0 -1
  52. package/docs/en/guides/topic-detail/generator/new/_meta.json +1 -5
  53. package/docs/en/guides/topic-detail/generator/plugin/_meta.json +1 -1
  54. package/docs/en/guides/troubleshooting/_meta.json +1 -6
  55. package/docs/en/tutorials/first-app/c03-css.mdx +1 -1
  56. package/docs/zh/apis/app/runtime/core/use-loader.mdx +1 -1
  57. package/docs/zh/community/blog/_meta.json +1 -6
  58. package/docs/zh/components/deploy.mdx +1 -1
  59. package/docs/zh/components/init-app.mdx +0 -1
  60. package/docs/zh/components/init-rspack-app.mdx +0 -1
  61. package/docs/zh/components/ssr-monitor.mdx +3 -0
  62. package/docs/zh/configure/_meta.json +1 -1
  63. package/docs/zh/configure/app/output/ssg.mdx +49 -139
  64. package/docs/zh/configure/app/tools/swc.mdx +1 -1
  65. package/docs/zh/configure/app/tools/tailwindcss.mdx +1 -1
  66. package/docs/zh/guides/advanced-features/_meta.json +0 -8
  67. package/docs/zh/guides/advanced-features/bff/_meta.json +1 -6
  68. package/docs/zh/guides/advanced-features/rsbuild-plugin.mdx +2 -2
  69. package/docs/zh/guides/advanced-features/rspack-start.mdx +8 -24
  70. package/docs/zh/guides/basic-features/_meta.json +31 -9
  71. package/docs/zh/guides/basic-features/css/_meta.json +1 -0
  72. package/docs/zh/guides/basic-features/css/css-in-js.mdx +34 -0
  73. package/docs/zh/guides/basic-features/css/css.mdx +25 -0
  74. package/docs/zh/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +3 -64
  75. package/docs/zh/guides/basic-features/data/_meta.json +1 -4
  76. package/docs/zh/guides/basic-features/data/data-fetch.mdx +98 -214
  77. package/docs/zh/guides/basic-features/data/data-write.mdx +54 -55
  78. package/docs/zh/guides/basic-features/debug/_meta.json +1 -0
  79. package/docs/zh/guides/basic-features/debug/rsdoctor.mdx +57 -0
  80. package/docs/zh/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +1 -1
  81. package/docs/zh/guides/basic-features/render/_meta.json +1 -0
  82. package/docs/zh/guides/basic-features/render/ssg.mdx +210 -0
  83. package/docs/zh/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +16 -26
  84. package/docs/zh/guides/basic-features/render/ssr.mdx +309 -0
  85. package/docs/zh/guides/{advanced-features/ssr/stream.mdx → basic-features/render/streaming-ssr.mdx} +22 -37
  86. package/docs/zh/guides/basic-features/routes.mdx +252 -237
  87. package/docs/zh/guides/basic-features/static-assets/_meta.json +1 -0
  88. package/docs/zh/guides/basic-features/static-assets.mdx +2 -6
  89. package/docs/zh/guides/basic-features/testing/_meta.json +1 -0
  90. package/docs/zh/guides/basic-features/testing/cypress.mdx +95 -0
  91. package/docs/zh/guides/basic-features/testing/jest.mdx +148 -0
  92. package/docs/zh/guides/basic-features/testing/playwright.mdx +112 -0
  93. package/docs/zh/guides/basic-features/testing/vitest.mdx +100 -0
  94. package/docs/zh/guides/concept/_meta.json +1 -4
  95. package/docs/zh/guides/concept/entries.mdx +80 -58
  96. package/docs/zh/guides/get-started/_meta.json +1 -7
  97. package/docs/zh/guides/get-started/introduction.mdx +2 -2
  98. package/docs/zh/guides/get-started/quick-start.mdx +1 -2
  99. package/docs/zh/guides/get-started/tech-stack.mdx +8 -10
  100. package/docs/zh/guides/get-started/upgrade.mdx +15 -1
  101. package/docs/zh/guides/topic-detail/framework-plugin/_meta.json +1 -1
  102. package/docs/zh/guides/topic-detail/generator/_meta.json +1 -1
  103. package/docs/zh/guides/topic-detail/generator/create/_meta.json +1 -5
  104. package/docs/zh/guides/topic-detail/generator/create/config.mdx +0 -10
  105. package/docs/zh/guides/topic-detail/generator/create/use.mdx +0 -1
  106. package/docs/zh/guides/topic-detail/generator/new/_meta.json +1 -5
  107. package/docs/zh/guides/topic-detail/generator/plugin/_meta.json +1 -1
  108. package/docs/zh/guides/troubleshooting/_meta.json +1 -6
  109. package/docs/zh/tutorials/first-app/c03-css.mdx +1 -1
  110. package/i18n.json +16 -4
  111. package/package.json +6 -6
  112. package/rspress.config.ts +1 -1
  113. package/src/components/ContentCard/index.tsx +1 -1
  114. package/src/components/Sandpack/index.tsx +1 -1
  115. package/src/components/ShowcaseList/index.tsx +1 -1
  116. package/src/i18n/index.ts +1 -1
  117. package/src/pages/index.tsx +2 -2
  118. package/docs/en/apis/app/hooks/config/storybook.mdx +0 -37
  119. package/docs/en/guides/advanced-features/ssg.mdx +0 -116
  120. package/docs/en/guides/advanced-features/ssr/_meta.json +0 -5
  121. package/docs/en/guides/advanced-features/ssr/index.mdx +0 -23
  122. package/docs/en/guides/advanced-features/ssr/stream.mdx +0 -248
  123. package/docs/en/guides/advanced-features/ssr/usage.mdx +0 -341
  124. package/docs/en/guides/advanced-features/ssr.mdx +0 -555
  125. package/docs/zh/apis/app/hooks/config/storybook.mdx +0 -38
  126. package/docs/zh/guides/advanced-features/ssg.mdx +0 -116
  127. package/docs/zh/guides/advanced-features/ssr/_meta.json +0 -5
  128. package/docs/zh/guides/advanced-features/ssr/index.mdx +0 -23
  129. package/docs/zh/guides/advanced-features/ssr/usage.mdx +0 -329
  130. /package/docs/en/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
  131. /package/docs/en/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
  132. /package/docs/en/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
  133. /package/docs/en/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
  134. /package/docs/en/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.mdx} +0 -0
  135. /package/docs/zh/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -0
  136. /package/docs/zh/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
  137. /package/docs/zh/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
  138. /package/docs/zh/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
  139. /package/docs/zh/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
  140. /package/docs/zh/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.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/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)