@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
@@ -1,24 +1,19 @@
1
- ---
2
- sidebar_position: 3
3
- title: Cache
4
- ---
1
+ # Rendering Cache
5
2
 
6
- # Render Cache
3
+ When developing applications, sometimes we cache computation results using hooks like React's `useMemo` and `useCallback`. By leveraging caching, we can reduce the number of computations, thus saving CPU resources and improving user experience.
7
4
 
8
- Sometimes we cache computation results, such as with the React useMemo, useCallback Hook. By caching, we can reduce the number of computations, thus reducing CPU resource usage and enhancing the user experience.
5
+ Modern.js supports caching server-side rendering (SSR) results, reducing the computational and rendering time during subsequent requests. This accelerates page load time and improves user experience. Additionally, caching lowers server load, conserves computational resources, and speeds up user access.
9
6
 
10
- Caching the results of server-side rendering (SSR) can reduce the computation and rendering time for each server request, enabling faster page load speeds and improving the user experience. It also lowers the server load, saves computational resources, and speeds up user access.
11
-
12
- :::info
13
- Need x.43.0+
7
+ :::tip
8
+ Requires version x.43.0+
14
9
  :::
15
10
 
16
11
  ## Configuration
17
12
 
18
- You can enable caching by configuring it in `server/cache.[t|j]s`:
13
+ Create a `server/cache.[t|j]s` file in your application and export the `cacheOption` configuration to enable SSR rendering cache:
19
14
 
20
15
  ```ts title="server/cache.ts"
21
- import type { CacheOption } from '@modern-js/runtime/server';
16
+ import type { CacheOption } from '@modern-js/runtime/server;
22
17
 
23
18
  export const cacheOption: CacheOption = {
24
19
  maxAge: 500, // ms
@@ -26,29 +21,27 @@ export const cacheOption: CacheOption = {
26
21
  };
27
22
  ```
28
23
 
29
- ## Configuration Explanation
24
+ ## Configuration Details
30
25
 
31
26
  ### Cache Configuration
32
27
 
33
- The caching policy is implemented based on [stale-while-revalidate](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control).
34
-
35
- During the `maxAge` period, cache content will be returned directly. After `maxAge` but within `staleWhileRevalidate`, the cache content will also be returned directly, but at the same time, re-rendering will be executed asynchronously.
28
+ The caching strategy implements [stale-while-revalidate](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control).
36
29
 
37
- **Object type**
30
+ Within the `maxAge` period, the cache content is directly returned. Exceeding `maxAge` but within `staleWhileRevalidate`, the cache content is still returned directly, but it re-renders asynchronously.
31
+
32
+ **Object Type**
38
33
 
39
34
  ```ts
40
35
  export interface CacheControl {
41
36
  maxAge: number;
42
-
43
37
  staleWhileRevalidate: number;
44
-
45
38
  customKey?: string | ((pathname: string) => string);
46
39
  }
47
40
  ```
48
41
 
49
- In this, customKey is used for custom cache key. By default, Modern.js will use the request pathname as key for caching, but in some cases, this may not meet your needs, so developers can customise it.
42
+ Here, `customKey` is the custom cache key. By default, Modern.js uses the request `pathname` as the cache key, but developers can define it when necessary.
50
43
 
51
- **Function type**
44
+ **Function Type**
52
45
 
53
46
  ```ts
54
47
  export type CacheOptionProvider = (
@@ -56,21 +49,18 @@ export type CacheOptionProvider = (
56
49
  ) => Promise<CacheControl | false> | CacheControl | false;
57
50
  ```
58
51
 
59
- Sometimes developers need to customise the cache key through req or when caching does not work for specific URLs, which can be handled using the function form, as shown in the following code:
52
+ Sometimes, developers need to use `req` to customize the cache key, or prevent caching for specific URLs. You can configure this as a function, as shown:
60
53
 
61
54
  ```ts title="server/cache.ts"
62
- import type { CacheOption, CacheOptionProvider } from '@modern-js/runtime/server';
55
+ import type { CacheOption, CacheOptionProvider } from '@modern-js/runtime/server;
63
56
 
64
57
  const provider: CacheOptionProvider = (req) => {
65
58
  const { url, headers, ... } = req;
66
-
67
- const key = computedKey(url, headers, ...);
68
-
69
59
  if(url.includes('no-cache=1')) {
70
60
  return false;
71
61
  }
72
62
 
73
-
63
+ const key = computedKey(url, headers, ...);
74
64
  return {
75
65
  maxAge: 500, // ms
76
66
  staleWhileRevalidate: 1000, // ms
@@ -81,16 +71,16 @@ const provider: CacheOptionProvider = (req) => {
81
71
  export const cacheOption: CacheOption = provider;
82
72
  ```
83
73
 
84
- **Mapping type**
74
+ **Mapping Type**
85
75
 
86
76
  ```ts
87
77
  export type CacheOptions = Record<string, CacheControl | CacheOptionProvider>;
88
78
  ```
89
79
 
90
- Sometimes, developers need to apply different caching policies for different routes. We also provide a mapping way for configuration, as shown in example below:
80
+ Sometimes, different routes require different caching strategies. We also offer a mapping configuration method, as shown below:
91
81
 
92
82
  ```ts title="server/cache.ts"
93
- import type { CacheOption } from '@modern-js/runtime/server';
83
+ import type { CacheOption } from '@modern-js/runtime/server;
94
84
 
95
85
  export const cacheOption: CacheOption = {
96
86
  '/home': {
@@ -99,9 +89,9 @@ export const cacheOption: CacheOption = {
99
89
  },
100
90
  '/about': {
101
91
  maxAge: 1000 * 60 * 60 * 24, // one day
102
- staleWhileRevalidate: 1000 * 60 * 60 * 24 * 2 // two day
92
+ staleWhileRevalidate: 1000 * 60 * 60 * 24 * 2 // two days
103
93
  },
104
- '*': (req) => { // If the above routes cannot be matched, it will match to '*'
94
+ '*': (req) => { // If no above route matches, this applies
105
95
  const { url, headers, ... } = req;
106
96
  const key = computedKey(url, headers, ...);
107
97
 
@@ -118,14 +108,13 @@ export const cacheOption: CacheOption = {
118
108
  - The route `http://xxx/about` will apply the second rule.
119
109
  - The route `http://xxx/abc` will apply the last rule.
120
110
 
121
- The above-mentioned `/home` and `/about` will be used as patterns for matching, which means that `/home/abc` will also comply with this rule.
122
- Simultaneously, you can also include regular expression syntax in it, such as `/home/.+`.
111
+ The above `/home` and `/about` are patterns, meaning `/home/abc` will also match. You can use regex in these patterns, such as `/home/.+`.
123
112
 
124
113
  ### Cache Container
125
114
 
126
- By default, Server will use memory for caching. But typically, services will be deployed on serverless. Each service access may be a new process, so caching cannot be applied every time.
115
+ By default, the server uses memory for caching. Typically, services are deployed in a Serverless container, creating a new process for each access, making it impossible to use the previous cache.
127
116
 
128
- Therefore, developers can also customise the cache container, which needs to implement the `Container` interface.
117
+ Thus, Modern.js allows developers to define custom cache containers. Containers must implement the `Container` interface:
129
118
 
130
119
  ```ts
131
120
  export interface Container<K = string, V = string> {
@@ -154,10 +143,11 @@ export interface Container<K = string, V = string> {
154
143
  }
155
144
  ```
156
145
 
157
- As an example in the following code, a developer can implement a Redis container.
146
+ Developers can implement a Redis cache container as shown below:
158
147
 
159
148
  ```ts
160
- import type { Container, CacheOption } from '@modern-js/runtime/server';
149
+ import Redis from 'ioredis';
150
+ import type { Container, CacheOption } from '@modern-js/runtime/server;
161
151
 
162
152
  class RedisContainer implements Container {
163
153
  redis = new Redis();
@@ -172,11 +162,11 @@ class RedisContainer implements Container {
172
162
  }
173
163
 
174
164
  async has(key: string): Promise<boolean> {
175
- return this.redis.has(key);
165
+ return this.redis.exists(key) > 0;
176
166
  }
177
167
 
178
168
  async delete(key: string): Promise<boolean> {
179
- return this.redis.delete(key);
169
+ return this.redis.del(key) > 0;
180
170
  }
181
171
  }
182
172
 
@@ -192,9 +182,7 @@ export const cacheOption: CacheOption = {
192
182
 
193
183
  ## Cache Identification
194
184
 
195
- When the rendering cache is activated, Modern.js will identify the cache status of the current request through the response header `x-render-cache`.
196
-
197
- The following is an example of a response.
185
+ When rendering cache is enabled, Modern.js identifies the cache status of the current request through the `x-render-cache` response header. Here's an example response:
198
186
 
199
187
  ```bash
200
188
  < HTTP/1.1 200 OK
@@ -207,11 +195,11 @@ The following is an example of a response.
207
195
  < Content-Length: 2937
208
196
  ```
209
197
 
210
- The `x-render-cache` may have the following values.
198
+ The `x-render-cache` header can have the following values:
211
199
 
212
- | Name | Description |
213
- | ------- | -------------------------------------------------------------------------- |
214
- | hit | Cache hit, returns cached content |
215
- | stale | Cache hit, but data is stale, returns cached content while rendering again |
216
- | expired | Cache hit, returns rendering result after re-rendering |
217
- | miss | Cache miss |
200
+ | Name | Description |
201
+ | ------- | ------------------------------------------------ |
202
+ | hit | Cache hit, returned cache content |
203
+ | stale | Cache hit, but data is stale, returned cache content and re-rendered asynchronously |
204
+ | expired | Cache expired, re-rendered and returned new content |
205
+ | miss | Cache missed |
@@ -0,0 +1,301 @@
1
+ # Server-Side Rendering
2
+
3
+ Server-Side Rendering (SSR) involves rendering the HTML content of a webpage-side and then sending the fully-rendered page to the browser. The browser only needs to display the page without additional rendering.
4
+
5
+ The main advantages are:
6
+
7
+ - **Improved First-Page Load Speed**: SSR generates a complete webpage on the server-side. The browser only needs to download the page content, avoiding additional rendering, thus improving the first-page load speed.
8
+ - **SEO-Friendly**: SSR can generate complete HTML content that search engines can directly index, thereby improving the website's ranking.
9
+
10
+ Developers might consider using SSR to render pages in the following scenarios:
11
+
12
+ 1. Websites that require high first-page load speed, such as e-commerce and news websites.
13
+ 2. Websites demanding high user experience, such as social networks and gaming websites.
14
+ 3. Websites with high SEO requirements, such as company websites and blogs.
15
+
16
+ In Modern.js, SSR is also available out of the box. Developers don't need to write complex server-side logic or worry about SSR maintenance or creating separate services.
17
+
18
+ Apart from the out-of-the-box SSR service, Modern.js also offers:
19
+
20
+ - Comprehensive SSR fallback strategies to ensure the page can run safely.
21
+ - Automatic segmentation of sub-routes with on-demand loading, reducing first-page resource size.
22
+ - Built-in caching system to address high server load issues.
23
+
24
+ ## Enabling SSR
25
+
26
+ Enabling SSR in Modern.js is straightforward. Simply set [`server.ssr`](/configure/app/server/ssr) to `true`:
27
+
28
+ ```ts title="modern.config.ts"
29
+ import { defineConfig } from '@modern-js/app-tools';
30
+
31
+ export default defineConfig({
32
+ server: {
33
+ ssr: true,
34
+ },
35
+ });
36
+ ```
37
+
38
+ ## Data Fetching
39
+
40
+ :::tip Prerequisite
41
+ If you're unfamiliar with how to use Data Loader or the concept of Client Loader, please read [Data Fetching](/guides/basic-features/data/data-fetch) first.
42
+ :::
43
+
44
+ ### Basic Usage
45
+
46
+ Modern.js provides Data Loader, enabling developers to fetch data isomorphically under both SSR and CSR. Each route module, such as `layout.tsx` and `page.tsx`, can define its own Data Loader:
47
+
48
+ ```ts title="src/routes/page.data.ts"
49
+ export const loader = () => {
50
+ return {
51
+ message: 'Hello World',
52
+ };
53
+ };
54
+ ```
55
+
56
+ In components, you can use hook APIs to access the data returned by the `loader` function:
57
+
58
+ ```tsx
59
+ import { useLoaderData } from '@modern-js/runtime/router';
60
+ export default () => {
61
+ const data = useLoaderData();
62
+ return <div>{data.message}</div>;
63
+ };
64
+ ```
65
+
66
+ ### Using Client Loader
67
+
68
+ :::info
69
+ This feature requires version x.36.0 or above. We recommend using the latest version of the framework.
70
+ :::
71
+
72
+ By default, in SSR applications, the `loader` function only executes on the server. However, in some scenarios, developers might want requests made on the client-side to bypass the SSR service and directly fetch data from the source. For example:
73
+
74
+ 1. Reducing network consumption on the client-side by directly fetching from the data source.
75
+ 2. The application has data cached on the client side and doesn't want to fetch data from the SSR service.
76
+
77
+ Modern.js supports adding a `.data.client` file, also named exported as `loader`, in SSR applications. If the Data Loader fails to execute on the server side, or when navigating on the client side, it will execute the `loader` function on the client side instead of sending a data request to the SSR service.
78
+
79
+ ```ts title="page.data.client.ts"
80
+ import cache from 'my-cache';
81
+
82
+ export async function loader({ params }) {
83
+ if (cache.has(params.id)) {
84
+ return cache.get(params.id);
85
+ }
86
+ const res = await fetch('URL_ADDRESS?id={params.id}');
87
+ return {
88
+ message: res.message,
89
+ }
90
+ }
91
+ ```
92
+
93
+ :::warning
94
+ To use Client Loader, there must be a corresponding Server Loader, and the Server Loader must be in a `.data` file, not a `.loader` file.
95
+ :::
96
+
97
+ ## SSR Fallback
98
+
99
+ In Modern.js, if an application encounters an error during SSR, it automatically falls back to CSR mode and re-fetches data, ensuring the page can display correctly. SSR fallback can occur for two main reasons:
100
+
101
+ 1. Data Loader execution error.
102
+ 2. React component rendering error on the server side.
103
+
104
+ ### Data Loader Execution Error
105
+
106
+ By default, if the `loader` function for a route throws an error, the framework renders the `<ErrorBoundary>` component directly on the server, displaying the error message. This is the default behavior of most frameworks.
107
+
108
+ Modern.js also supports customizing the fallback strategy through the `loaderFailureMode` field in the [`server.ssr`](/configure/app/server/ssr) configuration. Setting this field to `clientRender` immediately falls back to CSR mode and re-fetches the data.
109
+
110
+ If a Client Loader is defined for the route, it will be used to re-fetch the data. If re-rendering fails again, the `<ErrorBoundary>` component will be displayed.
111
+
112
+ {/* Todo Add a diagram */}
113
+
114
+ ### Component Rendering Error
115
+
116
+ If a component throws an error during rendering, Modern.js automatically falls back to CSR mode and re-fetches the data. If re-rendering fails again, the `<ErrorBoundary>` component will be displayed.
117
+
118
+ :::tip
119
+ The behavior of component rendering errors is unaffected by `loaderFailureMode` and will not execute the Client Loader on the browser side.
120
+ :::
121
+
122
+ {/* Todo Add a diagram */}
123
+
124
+ ## Logging and Monitoring
125
+
126
+ import Monitor from '@site-docs-en/components/ssr-monitor';
127
+
128
+ <Monitor />
129
+
130
+ ## Page Caching
131
+
132
+ Modern.js has built-in caching capabilities. Refer to [Rendering Cache](/guides/basic-features/render/ssr-cache) for details.
133
+
134
+ ## Differences in Runtime Environment
135
+
136
+ SSR applications run on both the server and the client, with differing Web and Node APIs.
137
+
138
+ When enabling SSR, Modern.js uses the same entry to build both SSR and CSR bundles. Therefore, having Web APIs in the SSR bundle or Node APIs in the CSR bundle can lead to runtime errors. This usually happens in two scenarios:
139
+
140
+ - There are issues in the application's own code.
141
+ - The dependency package contains side effects.
142
+
143
+ ### Issues with Own Code
144
+
145
+ This scenario often arises when migrating from CSR to SSR. CSR applications typically import Web APIs in the code. For example, an application might set up global event listeners:
146
+
147
+ ```tsx
148
+ document.addEventListener('load', () => {
149
+ console.log('document load');
150
+ });
151
+ const App = () => {
152
+ return <div>Hello World</div>;
153
+ };
154
+ export default App;
155
+ ```
156
+
157
+ In such cases, you can use Modern.js built-in environment variables `MODERN_TARGET` to remove unused code during the build:
158
+
159
+ ```ts
160
+ if (process.env.MODERN_TARGET === 'browser') {
161
+ document.addEventListener('load', () => {
162
+ console.log('document load');
163
+ });
164
+ }
165
+ ```
166
+
167
+ After packing in the development environment, the SSR and CSR bundles will compile as follows. Therefore, Web API errors will not occur in the SSR environment:
168
+
169
+ ```ts
170
+ // SSR Bundle
171
+ if (false) {
172
+ }
173
+
174
+ // CSR Bundle
175
+ if (true) {
176
+ document.addEventListener('load', () => {
177
+ console.log('document load');
178
+ });
179
+ }
180
+ ```
181
+
182
+ :::note
183
+ For more information, see [Environment Variables](/guides/basic-features/env-vars).
184
+ :::
185
+
186
+ ### Side Effects in Dependencies
187
+
188
+ This scenario can occur at any time in SSR applications because not all community packages support running in both environments. Some packages only need to run in one. For instance, importing package A that has a side effect using Web APIs:
189
+
190
+ ```ts title="packageA"
191
+ document.addEventListener('load', () => {
192
+ console.log('document load');
193
+ });
194
+
195
+ export const doSomething = () => {}
196
+ ```
197
+
198
+ Directly referencing this in a component will cause CSR to throw errors, even if you use environment variables to conditionally load the code. The side effects in the dependency will still execute.
199
+
200
+ ```tsx title="routes/page.tsx"
201
+ import { doSomething } from 'packageA';
202
+
203
+ export const Page = () => {
204
+ if (process.env.MODERN_TARGET === 'browser') {
205
+ doSomething();
206
+ }
207
+ return <div>Hello World</div>
208
+ }
209
+ ```
210
+
211
+ Modern.js supports distinguishing between SSR and CSR bundles by using `.server.` suffix files. You can create `.ts` and `.server.ts` files with the same name to create a proxy:
212
+
213
+ ```ts title="a.ts"
214
+ export { doSomething } from 'packageA';
215
+ ```
216
+
217
+ ```ts title="a.server.ts"
218
+ export const doSomething: any = () => {};
219
+ ```
220
+
221
+ Import `./a` in the file, and the SSR bundle will prioritize the `.server.ts` files, while the CSR bundle will prioritize the `.ts` files.
222
+
223
+ ```tsx title="routes/page.tsx"
224
+ import { doSomething } from './a'
225
+
226
+ export const Page = () => {
227
+ doSomething();
228
+ return <div>Hello World</div>
229
+ }
230
+ ```
231
+
232
+ ## Common Issues
233
+
234
+ ### Ensuring Consistent Rendering
235
+
236
+ In SSR applications, it is crucial to ensure that the rendering results on the server are consistent with the hydration results in the browser. Inconsistent rendering may lead to unexpected outcomes. Here’s an example demonstrating issues when SSR and CSR render differently. Add the following code to your component:
237
+
238
+ ```tsx
239
+ {
240
+ typeof window !== 'undefined' ? <div>browser content</div> : null;
241
+ }
242
+ ```
243
+
244
+ After starting the application and visiting the page, you will notice a warning in the browser console:
245
+
246
+ ```sh
247
+ Warning: Expected server HTML to contain a matching <div> in <div>.
248
+ ```
249
+
250
+ This warning is caused by a mismatch between the React hydrate results and the SSR rendering results. Although the current page appears normal, complex applications may experience DOM hierarchy disruptions or style issues.
251
+
252
+ :::info
253
+ For more information on React hydrate logic, refer to [here](https://zh-hans.react.dev/reference/react-dom/hydrate).
254
+ :::
255
+
256
+ The application needs to maintain consistency between SSR and CSR rendering results. If inconsistencies occur, it indicates that some content should not be rendered by SSR. Modern.js provides the `<NoSSR>` utility component for such scenarios:
257
+
258
+ ```ts
259
+ import { NoSSR } from '@modern-js/runtime/ssr';
260
+ ```
261
+
262
+ Wrap elements that should not be server-side rendered with the `NoSSR` component:
263
+
264
+ ```tsx
265
+ <NoSSR>
266
+ <div>browser content</div>
267
+ </NoSSR>
268
+ ```
269
+
270
+ After modifying the code, refresh the page and notice that the previous warning has disappeared. Open the browser's developer tools and check the Network tab. The returned HTML document will not contain the content wrapped by the `NoSSR` component.
271
+
272
+ In practical scenarios, some UI displays might be affected by the user's device, such as [UA](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) information. Modern.js also provides APIs like [`useRuntimeContext`](/apis/app/runtime/core/use-runtime-context), allowing components to access complete request information and maintaining SSR and CSR rendering consistency.
273
+
274
+ ### Attention to Memory Leaks
275
+
276
+ :::warning Alert
277
+ In SSR scenarios, developers need to pay special attention to memory leaks. Even minor memory leaks can significantly impact services after many requests.
278
+ :::
279
+
280
+ With SSR, each browser request triggers server-side component rendering. Therefore, you should avoid defining any data structures that continually grow globally, subscribing to global events, or creating non-disposable streams.
281
+
282
+ For example, when using [redux-observable](https://redux-observable.js.org/), developers accustomed to CSR might code as follows:
283
+
284
+ ```tsx
285
+ /* Code is just an example and not executable */
286
+ import { createEpicMiddleware, combineEpics } from 'redux-observable';
287
+
288
+ const epicMiddleware = createEpicMiddleware();
289
+ const rootEpic = combineEpics();
290
+
291
+ export default function Test() {
292
+ epicMiddleware.run(rootEpic);
293
+ return <div>Hello Modern.js</div>;
294
+ }
295
+ ```
296
+
297
+ In this case, the `epicMiddleware` instance is created outside the component, and `epicMiddleware.run` is called within the component.
298
+
299
+ This code does not cause issues on the client-side. However, in SSR, the Middleware instance remains non-disposable. Each time the component renders, calling `epicMiddleware.run(rootEpic)` adds new event bindings internally, causing the entire object to grow continuously, ultimately affecting application performance.
300
+
301
+ Such issues are not easily noticed in CSR. When transitioning from CSR to SSR, if you're unsure whether your application has such hidden pitfalls, consider stress testing the application.