@modern-js/main-doc 0.0.0-nightly-20240827170702 → 0.0.0-nightly-20240829170706

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/docs/en/apis/app/runtime/core/use-loader.mdx +1 -1
  2. package/docs/en/components/ssr-monitor.mdx +3 -0
  3. package/docs/en/configure/app/output/ssg.mdx +52 -141
  4. package/docs/en/guides/advanced-features/_meta.json +0 -7
  5. package/docs/en/guides/basic-features/_meta.json +7 -1
  6. package/docs/en/guides/basic-features/data/data-fetch.mdx +134 -235
  7. package/docs/en/guides/basic-features/data/data-write.mdx +66 -77
  8. package/docs/en/guides/basic-features/render/_meta.json +1 -0
  9. package/docs/en/guides/basic-features/render/ssg.mdx +208 -0
  10. package/docs/en/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +38 -50
  11. package/docs/en/guides/basic-features/render/ssr.mdx +301 -0
  12. package/docs/en/guides/basic-features/render/streaming-ssr.mdx +230 -0
  13. package/docs/en/guides/basic-features/routes.mdx +275 -263
  14. package/docs/en/guides/concept/entries.mdx +9 -2
  15. package/docs/zh/apis/app/runtime/core/use-loader.mdx +1 -1
  16. package/docs/zh/components/ssr-monitor.mdx +3 -0
  17. package/docs/zh/configure/app/output/ssg.mdx +49 -139
  18. package/docs/zh/guides/advanced-features/_meta.json +0 -7
  19. package/docs/zh/guides/basic-features/_meta.json +7 -1
  20. package/docs/zh/guides/basic-features/data/data-fetch.mdx +98 -213
  21. package/docs/zh/guides/basic-features/data/data-write.mdx +54 -55
  22. package/docs/zh/guides/basic-features/render/_meta.json +1 -0
  23. package/docs/zh/guides/basic-features/render/ssg.mdx +210 -0
  24. package/docs/zh/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +16 -26
  25. package/docs/zh/guides/basic-features/render/ssr.mdx +309 -0
  26. package/docs/zh/guides/{advanced-features/ssr/stream.mdx → basic-features/render/streaming-ssr.mdx} +22 -37
  27. package/docs/zh/guides/basic-features/routes.mdx +252 -237
  28. package/docs/zh/guides/concept/entries.mdx +6 -3
  29. package/package.json +6 -6
  30. package/docs/en/guides/advanced-features/ssg.mdx +0 -116
  31. package/docs/en/guides/advanced-features/ssr/_meta.json +0 -1
  32. package/docs/en/guides/advanced-features/ssr/index.mdx +0 -23
  33. package/docs/en/guides/advanced-features/ssr/stream.mdx +0 -248
  34. package/docs/en/guides/advanced-features/ssr/usage.mdx +0 -341
  35. package/docs/en/guides/advanced-features/ssr.mdx +0 -555
  36. package/docs/zh/guides/advanced-features/ssg.mdx +0 -116
  37. package/docs/zh/guides/advanced-features/ssr/_meta.json +0 -1
  38. package/docs/zh/guides/advanced-features/ssr/index.mdx +0 -23
  39. package/docs/zh/guides/advanced-features/ssr/usage.mdx +0 -329
@@ -5,15 +5,17 @@ sidebar_position: 4
5
5
 
6
6
  # 数据写入
7
7
 
8
- Data Loader 章节中,介绍了 Modern.js 获取数据的方式,你可能会遇到两个问题:
9
- 1. 如何更新 Data Loader 中的数据?
8
+ [数据获取](/guides/basic-features/data/data-fetch)章节中,介绍了 Modern.js 获取数据的方式,你可能会遇到两个问题:
9
+
10
+ 1. 如何更新 Data Loader 返回的数据?
10
11
  2. 如何将新的数据传递到服务器?
11
12
 
12
- EdenX 对此的解决方案是 DataAction。
13
+ Modern.js 中,可以通过 Data Action 解决和实现。
14
+
15
+ ## 什么是 Data Action
13
16
 
14
- ## 基本示例
17
+ Modern.js 推荐使用[约定式路由](/guides/basic-features/routes)做路由的管理,每个路由组件(`layout.ts`,`page.ts` 或 `$.tsx`)都可以有一个同名的 `.data` 文件。这些文件可以导出一个 `action` 函数,我们称为 Data Action,开发者可以在合适的时机调用它:
15
18
 
16
- Data Action 和 Data Loader 一样,也是基于约定式路由的,通过 Modern.js 的[约定式(嵌套)路由](/guides/basic-features/routes#约定式路由),每个路由组件(`layout.ts`,`page.ts` 或 `$.tsx`)可以有一个同名的 `data` 文件,`data` 文件中可以导出一个命名为 `action` 的函数。
17
19
  ```bash
18
20
  .
19
21
  └── routes
@@ -21,17 +23,21 @@ Data Action 和 Data Loader 一样,也是基于约定式路由的,通过 Mod
21
23
  ├── layout.tsx
22
24
  └── layout.data.ts
23
25
  ```
24
- 在文件中定义以下代码:
26
+
27
+ 在 `routes/user/layout.data.ts` 文件中,可以导出一个 Data Action 函数:
28
+
25
29
  ```ts title="routes/user/layout.data.ts"
26
30
  import type { ActionFunction } from '@modern-js/runtime/router';
27
31
 
28
32
  export const action: ActionFunction = ({ request }) => {
29
- const newUser = await request.json();
30
- const name = newUser.name;
31
- return updateUserProfile(name);
33
+ const newUser = await request.json();
34
+ const name = newUser.name;
35
+ return updateUserProfile(name);
32
36
  }
33
37
  ```
34
38
 
39
+ 在路由组件中,你可以通过 `useFetcher` 获取对应 `submit` 函数,执行并触发 Data Action:
40
+
35
41
  ```tsx title="routes/user/layout.tsx"
36
42
  import {
37
43
  useFetcher,
@@ -64,41 +70,24 @@ export default () => {
64
70
  }
65
71
  ```
66
72
 
67
- 这里当执行 submit 后,会触发定义的 action 函数;在 action 函数中,可以通过 request (request.json,request.formData)获取提交的数据,获取数据后,再发送数据到服务端。
73
+ 当执行 `submit` 后,会触发定义的 `action` 函数。在 `action` 函数中,可以通过[入参](/guides/basic-features/data/data-write.html#入参)获取提交的数据,最终发送数据到服务端。
68
74
 
69
- action 函数执行完,会执行 loader 函数代码,并更新对应的数据和视图。
75
+ `action` 函数执行完后,Modern.js 将自动执行 `loader` 函数代码,并更新对应的数据和视图。
70
76
 
71
77
  ![action flow](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-flow.png)
72
78
 
73
-
74
-
75
- ## 为什么要提供 Data Action
76
-
77
- Modern.js 中提供 Data Action 主要是为了使 UI 和服务器的状态能保持同步,通过这种方式可以减少状态管理的负担,
78
- 传统的状态管理方式,会在客户端和远程分别持有状态:
79
-
80
- ![traditional state manage](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-state-manage.png)
81
-
82
- 而在 Modern.js 中,我们希望通过 Loader 和 Action 帮助开发者自动的同步客户端和服务端的状态:
83
-
84
- ![state manage](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-state-manage1.png)
85
-
86
- 如果项目中组件共享的数据主要来自于服务端的状态,则无需在项目引入客户端状态管理库。可以使用 Data Loader 请求数据,通过 [`useRouteLoaderData`](/guides/basic-features/data/data-fetch.md) 在子组件中共享数据,使用 Data Action 修改和同步服务端的状态。
87
-
88
-
89
-
90
79
  ## `action` 函数
91
80
 
92
- 与 `loader` 函数一样,`action` 函数有两个入参,`params` 和 `request`:
81
+ 与 `loader` 函数一样,`action` 函数有两个入参,`params` 和 `request`。
93
82
 
94
- ### `params`
83
+ ### params
95
84
 
96
- 当路由文件通过 `[]` 时,会作为[动态路由](/guides/basic-features/routes#动态路由),动态路由片段会作为参数传入 `action` 函数:
85
+ `params` 是当路由为[动态路由](/guides/basic-features/routes#动态路由)时动态路由片段,会作为参数传入 `action` 函数:
97
86
 
98
- ```tsx
99
- // routes/user/[id]/page.data.ts
87
+ ```tsx title="routes/user/[id]/page.data.ts"
100
88
  import { ActionFunctionArgs } from '@modern-js/runtime/router';
101
89
 
90
+ // 访问 /user/123 时,函数的参数为 `{ params: { id: '123' } }`
102
91
  export const action = async ({ params }: ActionFunctionArgs) => {
103
92
  const { id } = params;
104
93
  const res = await fetch(`https://api/user/${id}`);
@@ -106,18 +95,11 @@ export const action = async ({ params }: ActionFunctionArgs) => {
106
95
  };
107
96
  ```
108
97
 
109
- 当访问 `/user/123` 时,`action` 函数的参数为 `{ params: { id: '123' } }`。
110
-
98
+ ### request
111
99
 
112
- ### `request`
100
+ `request` 是一个 [Fetch Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) 实例。通过 `request`,可以在 action 函数中获取到浏览器端提交的数据,如 `request.json()`,`request.formData()`,`request.json()` 等。具体使用哪个 API,请参考[数据类型](#数据类型)。
113
101
 
114
- `request` 是一个 [Fetch Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) 实例。
115
-
116
- 通过 `request`,可以在 action 函数中获取到客户端提交的数据,如 `request.json()`,`request.formData()`,`request.json()` 等,
117
- 具体应该使用哪个 API,请参考[数据类型](#数据类型)。
118
-
119
- ```tsx
120
- // routes/user/[id]/page.data.ts
102
+ ```tsx title="routes/user/[id]/page.data.ts"
121
103
  import { ActionFunctionArgs } from '@modern-js/runtime/router';
122
104
 
123
105
  export const action = async ({ request }: ActionFunctionArgs) => {
@@ -131,13 +113,12 @@ export const action = async ({ request }: ActionFunctionArgs) => {
131
113
  `action` 函数的返回值可以是任何可序列化的内容,也可以是一个 [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) 实例,
132
114
  可以通过 [`useActionData`](https://reactrouter.com/en/main/hooks/use-action-data) 访问 response 中内容。
133
115
 
134
-
135
116
  ## useSubmit 和 useFetcher
136
117
 
137
118
  ### 区别
138
119
 
139
- 你可以通过 [`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit) 或 [`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher) 调用 action,它们的区别是通过
140
- `useSubmit` 调用 action,会触发浏览器的导航,通过 `useFetcher` 则不会触发浏览器的导航。
120
+ 你可以通过 [`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit) 或 [`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher) 调用 Data Action。它们的区别是通过
121
+ `useSubmit` 调用,会触发浏览器的导航,通过 `useFetcher` 则不会触发浏览器的导航。
141
122
 
142
123
  useSubmit:
143
124
 
@@ -147,19 +128,19 @@ submit(null, { method: "post", action: "/logout" });
147
128
  ```
148
129
 
149
130
  useFetcher:
131
+
150
132
  ```ts
151
133
  const { submit } = useFetcher();
152
134
  submit(null, { method: "post", action: "/logout" });
153
135
  ```
154
136
 
155
- `submit` 函数有两个入参,`method` `action`,`method` 相当于表单提交时的 `method`,大部分写入数据的场景下,`method` 可以传入 `post`,
156
- `action` 用来指定触发哪个路由组件的 `action`,如果未传入 `action` 入参,默认会触发当前路由组件的 action,即 `user/page.tsx` 组件或子组件中执行 submit,
157
- 会触发 `user/page.data.ts` 中定义的 action。
137
+ `submit` 函数有两个入参,第一个入参是传递到服务端的 `formData`。第二个入参是可选参数,其中
138
+ - `method` 相当于表单提交时的 `method`,大部分写入数据的场景下,`method` 可以传入 `post`。
139
+ - `action` 用来指定触发哪个路由组件的 Data Action,如果未传入 `action` 入参,默认会触发当前路由组件的 action,即 `user/page.tsx` 组件或子组件中执行 submit,会触发 `user/page.data.ts` 中定义的 action。
158
140
 
159
141
  :::info
160
- 这两个 API 更多的信息可参考相关文档:
161
- - [`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit)
162
- - [`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher)
142
+
143
+ 更多 API 的信息可参考相关文档:[`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit)、[`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher)。
163
144
 
164
145
  :::
165
146
 
@@ -167,7 +148,9 @@ submit(null, { method: "post", action: "/logout" });
167
148
  ### 数据类型
168
149
 
169
150
  `submit` 函数的第一个入参,可以接受不同类型的值。
151
+
170
152
  如 `FormData`:
153
+
171
154
  ```ts
172
155
  let formData = new FormData();
173
156
  formData.append("cheese", "gouda");
@@ -176,6 +159,7 @@ submit(formData);
176
159
  ```
177
160
 
178
161
  或 `URLSearchParams` 类型的值:
162
+
179
163
  ```ts
180
164
  let searchParams = new URLSearchParams();
181
165
  searchParams.append("cheese", "gouda");
@@ -183,7 +167,8 @@ submit(searchParams);
183
167
  // In the action, you can get the data by request.json
184
168
  ```
185
169
 
186
- 或任意 `URLSearchParams` 构造函数可接受的值
170
+ 或任意 `URLSearchParams` 构造函数可接受的值:
171
+
187
172
  ```ts
188
173
  submit("cheese=gouda&toasted=yes");
189
174
  submit([
@@ -207,7 +192,7 @@ submit(
207
192
  // In the action, you can get the data by request.formData
208
193
  ```
209
194
 
210
- 也可以指定为 json 编码:
195
+ 你也可以通过第二个参数,指定为编码方式:
211
196
 
212
197
  ```tsx
213
198
  submit(
@@ -224,12 +209,26 @@ submit('{"key":"value"}', {
224
209
  ```
225
210
 
226
211
  或提交纯文本:
212
+
227
213
  ```ts
228
214
  submit("value", { method: "post", encType: "text/plain" });
229
215
  // In the action, you can get the data by request.text
230
216
  ```
231
217
 
218
+ ## 为什么要提供 Data Action
219
+
220
+ Modern.js 中提供 Data Action 主要是为了使 UI 和服务器的状态能保持同步,通过这种方式可以减少状态管理的负担,
221
+ 传统的状态管理方式,会在浏览器端和远程分别持有状态:
222
+
223
+ ![traditional state manage](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-state-manage.png)
224
+
225
+ 而在 Modern.js 中,我们希望通过 Loader 和 Action 帮助开发者自动的同步浏览器端和服务端的状态:
226
+
227
+ ![state manage](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-state-manage1.png)
228
+
229
+ 如果项目中组件共享的数据主要来自于服务端的状态,则无需在项目引入浏览器端状态管理库。可以使用 Data Loader 请求数据,通过 [`useRouteLoaderData`](/guides/basic-features/data/data-fetch.md) 在子组件中共享数据,使用 Data Action 修改和同步服务端的状态。
230
+
232
231
 
233
232
  ## CSR 和 SSR
234
233
 
235
- 与 Data Loader 一样,SSR 项目中,Data Action 是在服务端执行的(框架会自动发请求触发 Data Action),而在 CSR 项目中,Data Action 是在客户端执行的。
234
+ 与 Data Loader 一样,SSR 项目中,Data Action 是在服务端执行的(框架会自动发请求触发 Data Action),而在 CSR 项目中,Data Action 是在浏览器端执行的。
@@ -0,0 +1 @@
1
+ ["ssr", "streaming-ssr", "ssr-cache", "ssg"]
@@ -0,0 +1,210 @@
1
+ ---
2
+ title: 静态站点生成(SSG)
3
+ ---
4
+
5
+ # 静态站点生成(SSG)
6
+
7
+ SSG(Static Site Generation)是一种基于数据与模板,在构建时渲染完整静态网页的技术解决方案。这意味着在生产环境中,页面默认就是有内容的,并且可以被 CDN 缓存。对于无需数据的页面,SSG 可以提供更好的性能和更高的安全性。
8
+
9
+ ## 启用 SSG
10
+
11
+ 我们首先需要执行 `pnpm run new` 启用 SSG 功能:
12
+
13
+ ```bash
14
+ ? 请选择你想要的操作 启用可选功能
15
+ ? 请选择功能名称 启用「SSG」功能
16
+ ```
17
+
18
+ 执行命令后,在 `modern.config.ts` 中注册 SSG 插件:
19
+
20
+ ```ts title="modern.config.ts"
21
+ import { ssgPlugin } from '@modern-js/plugin-ssg';
22
+
23
+ export default defineConfig({
24
+ output: {
25
+ ssg: true,
26
+ },
27
+ plugins: [..., ssgPlugin()],
28
+ });
29
+ ```
30
+
31
+ ## 开发环境调试
32
+
33
+ SSG 也是在 Node.js 环境渲染页面,因此我们可以在**开发阶段开启 SSR**,提前暴露代码问题,验证 SSG 渲染效果:
34
+
35
+ ```ts title="modern.config.ts"
36
+ export default defineConfig({
37
+ server: {
38
+ ssr: process.env.NODE_ENV === 'development',
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## 在约定式路由中使用
44
+
45
+ **约定式路由**中,Modern.js 根据入口下的文件结构生成路由,因此框架能够收集完整的路由信息。
46
+
47
+ ### 基本用法
48
+
49
+ 例如,以下是一个使用约定式路由的项目目录结构:
50
+
51
+ ```bash
52
+ .
53
+ └── routes
54
+ ├── layout.tsx
55
+ ├── page.tsx
56
+ └── user
57
+ ├── layout.tsx
58
+ ├── page.tsx
59
+ └── profile
60
+ └── page.tsx
61
+ ```
62
+
63
+ 上述文件目录将会生成以下三条路由:
64
+
65
+ - `/`
66
+ - `/user`
67
+ - `/user/profile`
68
+
69
+ :::tip
70
+ 如果还不了解约定式路由的规则,可以先查看[路由方案](/guides/basic-features/routes)。
71
+
72
+ :::
73
+
74
+ 在 `src/routes/page.tsx` 中添加组件代码:
75
+
76
+ ```jsx title="src/routes/page.tsx"
77
+ export default () => {
78
+ return <div>Index Page</div>;
79
+ };
80
+ ```
81
+
82
+ 在项目根路径下执行 `pnpm run dev` 命令,查看 `dist/` 目录,此时只生成一个 HTML 文件 `main/index.html`。
83
+
84
+ 在项目根路径下执行 `pnpm run build` 命令,构建完成后,查看 `dist/` 目录,此时生成 `main/index.html`、`main/user/index.html` 和 `main/user/profile/index.html` 三个 HTML 文件,内容分别对应上述三条路由。
85
+
86
+ **约定式路由**中的每一条路由,都会生成一个单独的 HTML 文件。查看 `main/index.html`,可以发现包含 `Index Page` 的文本内容,这正是 SSG 的效果。
87
+
88
+ 执行 `pnpm run serve` 启动项目后,访问页面,在浏览器我们工具的 Network 窗口,查看请求返回的文档,文档包含组件渲染后的完整页面内容。
89
+
90
+ ### 阻止默认行为
91
+
92
+ 默认情况下,**约定式路由**的路由会全部开启 SSG。Modern.js 提供了另一个字段,用来阻止默认的 SSG 行为。
93
+
94
+ 例如以下目录结构,`/`、`/user`、`/user/profle` 三条路由都开启 SSG:
95
+
96
+ ```bash
97
+ .
98
+ ├── src
99
+ │ └── routes
100
+ │ ├── layout.tsx
101
+ │ ├── page.tsx
102
+ │ └── user
103
+ │ ├── layout.tsx
104
+ │ ├── page.tsx
105
+ │ └── profile
106
+ │ └── page.tsx
107
+ ```
108
+
109
+ 可以通过配置 `preventDefault` 来禁用某些路由的默认行为。进行下面配置后,最终只会生成 `/`、`/user/profle` 两条路由的 SSG 页面:
110
+
111
+ ```js
112
+ export default defineConfig({
113
+ output: {
114
+ ssg: {
115
+ preventDefault: ['/user'],
116
+ },
117
+ },
118
+ });
119
+ ```
120
+
121
+ ## 在自控式路由中使用
122
+
123
+ **自控式路由**是通过组件代码定义路由,需要应用运行起来才能获取准确的路由信息。因此,无法开箱即用的使用 SSG 功能。开发者需要通过配置告知 Modern.js 框架,哪些路由需要开启 SSG 功能。
124
+
125
+ 例如有以下代码,包含多条路由,设置 `output.ssg` 为 `true` 时,默认只会渲染入口路由即 `/`:
126
+
127
+ import SelfRouteExample from '@site-docs/components/self-route-example';
128
+
129
+ <SelfRouteExample />
130
+
131
+ 如果我们希望同时开启 `/about` 的 SSG 功能,可以配置 `output.ssg`:
132
+
133
+ ```ts title="modern.config.ts"
134
+ export default defineConfig({
135
+ output: {
136
+ ssg: {
137
+ routes: ['/', '/about'],
138
+ },
139
+ },
140
+ });
141
+ ```
142
+
143
+ 执行 `pnpm run build` 后,可以看到 `dist/` 目录中,新增了一个 `main/about/index.html` 文件。
144
+
145
+ 执行 `pnpm run serve` 启动项目后,访问页面,在浏览器我们工具的 Network 窗口,查看请求返回的文档,文档包含组件渲染后的完整页面内容。
146
+
147
+ :::info
148
+ 以上仅介绍了单入口的情况,更多相关内容可以查看 [API 文档](/configure/app/output/ssg)。
149
+ :::
150
+
151
+ ## 添加路由参数
152
+
153
+ 在 Modern.js 中,部分路由可能是动态的,例如自控式路由中的 `/user/:id` 或是约定式路由中 `user/[id]/page.tsx` 文件生成的路由。
154
+
155
+ 可以在 `output.ssg` 中配置具体的参数,渲染指定参数的路由,例如:
156
+
157
+ ```js
158
+ export default defineConfig({
159
+ output: {
160
+ ssg: {
161
+ routes: [
162
+ {
163
+ url: '/user/:id',
164
+ params: [{
165
+ id: 'modernjs',
166
+ }],
167
+ },
168
+ ],
169
+ },
170
+ },
171
+ });
172
+ ```
173
+
174
+ 此时,`/user/modernjs` 路由会被渲染,并且在渲染时,会将 `id` 参数传递给组件。当配置多个值时,对应会生成多张页面。
175
+
176
+ :::note
177
+ 动态路由和 SSG 的组合,在根据 CMS 系统数据变更,实时生成静态页面时非常有用。
178
+ :::
179
+
180
+
181
+ ## 配置渲染请求头
182
+
183
+ Modern.js 支持为具体入口或路由配置请求头,例如:
184
+
185
+ ```js
186
+ export default defineConfig({
187
+ output: {
188
+ ssg: {
189
+ headers: {
190
+ "x-tt-env": "ppe_modernjs"
191
+ },
192
+ routes: [
193
+ '/',
194
+ {
195
+ url: '/about',
196
+ headers: {
197
+ "from": "modern-website"
198
+ },
199
+ },
200
+ ],
201
+ },
202
+ },
203
+ });
204
+ ```
205
+
206
+ 上述配置中,为所有路由设置了 `x-tt-env` 请求头,单独为 `/about` 路由设置了 `from` 请求头。
207
+
208
+ :::tip
209
+ 路由中设置的 `headers` 会覆盖入口中设置的 `headers`。
210
+ :::
@@ -1,23 +1,20 @@
1
1
  ---
2
- sidebar_position: 3
3
- title: 缓存
2
+ title: 渲染缓存
4
3
  ---
5
4
 
6
5
  # 渲染缓存
7
6
 
8
- 有时我们会将计算结果进行缓存,例如 React useMemo, useCallback Hook
9
- 通过缓存我们可以减少计算的次数来减少 CPU 资源占用,提高用户体验。
7
+ 在开发应用时,有时我们会将计算结果进行缓存,例如使用 React `useMemo`、`useCallback` Hook。通过缓存我们可以减少计算的次数来减少 CPU 资源占用,提高用户体验。
10
8
 
11
- 通过将服务器端渲染(SSR)结果进行缓存能够减少服务器每次请求时的计算和渲染时间,从而加速页面加载速度,提高用户体验。
12
- 降低服务端负载,节省计算资源,提高用户访问速度。
9
+ Modern.js 支持将服务器端渲染(SSR)结果进行缓存,减少服务器每次请求时的计算和渲染时间,从而加速页面加载速度,提高用户体验。同时,缓存也能降低服务端负载,节省计算资源,提高用户访问速度。
13
10
 
14
- :::info
11
+ :::tip
15
12
  需要 x.43.0+
16
13
  :::
17
14
 
18
15
  ## 配置方式
19
16
 
20
- `server/cache.[t|j]s` 中配置缓存即可开启缓存:
17
+ 在应用中创建 `server/cache.[t|j]s` 文件,并导出 `cacheOption` 配置缓存即可开启 SSR 渲染缓存:
21
18
 
22
19
  ```ts title="server/cache.ts"
23
20
  import type { CacheOption } from '@modern-js/runtime/server';
@@ -41,14 +38,12 @@ export const cacheOption: CacheOption = {
41
38
  ```ts
42
39
  export interface CacheControl {
43
40
  maxAge: number;
44
-
45
41
  staleWhileRevalidate: number;
46
-
47
42
  customKey?: string | ((pathname: string) => string);
48
43
  }
49
44
  ```
50
45
 
51
- 其中 customKey 为自定义缓存 key。默认情况下 Modern.js 将会把请求 pathname 作为 key 进行缓存,但在某些情况下这不能满足你的需求,开发者可以进行自定义。
46
+ 其中 `customKey` 为自定义缓存 key。默认情况下 Modern.js 将会把请求 `pathname` 作为 key 进行缓存,但在某些情况下这不能满足你的需求,开发者可以进行自定义。
52
47
 
53
48
  **Function 类型**
54
49
 
@@ -58,7 +53,7 @@ export type CacheOptionProvider = (
58
53
  ) => Promise<CacheControl | false> | CacheControl | false;
59
54
  ```
60
55
 
61
- 有时开发者需要通过 req 来自定义缓存 key,或者特定 url 时缓存不生效,可以配置为函数的形式进行处理, 例如以下代码:
56
+ 有时开发者需要通过 `req` 来自定义缓存 key,或者特定 URL 时缓存不生效,可以配置为函数的形式进行处理, 例如以下代码:
62
57
 
63
58
  ```ts title="server/cache.ts"
64
59
 
@@ -66,13 +61,11 @@ import type { CacheOption, CacheOptionProvider } from '@modern-js/runtime/server
66
61
 
67
62
  const provider: CacheOptionProvider = (req) => {
68
63
  const { url, headers, ... } = req;
69
-
70
- const key = computedKey(url, headers, ...);
71
-
72
64
  if(url.includes('no-cache=1')) {
73
65
  return false;
74
66
  }
75
67
 
68
+ const key = computedKey(url, headers, ...);
76
69
  return {
77
70
  maxAge: 500, // ms
78
71
  staleWhileRevalidate: 1000, // ms
@@ -89,7 +82,7 @@ export const cacheOption: CacheOption = provider;
89
82
  export type CacheOptions = Record<string, CacheControl | CacheOptionProvider>;
90
83
  ```
91
84
 
92
- 有时开发者面对不同的路由需要应用不同的缓存策略。我们也提供一种映射的方式进行配置, 以下列代码为例子
85
+ 有时开发者面对不同的路由需要应用不同的缓存策略。我们也提供一种映射的方式进行配置, 以下列代码为例:
93
86
 
94
87
  ```ts title="server/cache.ts"
95
88
  import type { CacheOption } from '@modern-js/runtime/server';
@@ -120,14 +113,13 @@ export const cacheOption: CacheOption = {
120
113
  - 路由 `http://xxx/about` 将会应用第二条规则。
121
114
  - 路由 `http://xxx/abc` 将会应用最后一条规则。
122
115
 
123
- 上述 `/home` 和 `/about` 将会作为模式进行匹配,这意味着 `/home/abc` 也会匹配上该规则。
124
- 同时,你也可以在其中编写正则语法:`/home/.+`
116
+ 上述 `/home` 和 `/about` 将会作为模式进行匹配,这意味着 `/home/abc` 也会匹配上该规则。同时,你也可以在其中编写正则语法:`/home/.+`
125
117
 
126
118
  ### 缓存容器
127
119
 
128
- 默认情况下,Server 将会使用内存进行缓存。但通常情况下服务将会部署在 serverless 上。每一次的服务访问可能都是一个新的进程,这样每次访问都不能应用缓存
120
+ 默认情况下,Server 将会使用内存进行缓存。但通常情况下服务将会部署在 Serverless 容器上。每一次的服务访问可能都是一个新的进程,这样每次访问都不能应用缓存。
129
121
 
130
- 故开发者也可以自定义缓存容器,容器需实现接口 `Container`
122
+ 因此,Modern.js 支持开发者自定义缓存容器,容器需实现接口 `Container`:
131
123
 
132
124
  ```ts
133
125
  export interface Container<K = string, V = string> {
@@ -156,7 +148,7 @@ export interface Container<K = string, V = string> {
156
148
  }
157
149
  ```
158
150
 
159
- 以下面代码为例,开发者可实现一个 redis 容器。
151
+ 以下面代码为例,开发者可实现一个 redis 缓存容器。
160
152
 
161
153
  ```ts
162
154
  import type { Container, CacheOption } from '@modern-js/runtime/server';
@@ -194,9 +186,7 @@ export const cacheOption: CacheOption = {
194
186
 
195
187
  ## 缓存标识
196
188
 
197
- 当开启渲染缓存后,Modern.js 将通过响应头 `x-render-cache` 来标识当前请求的缓存状态。
198
-
199
- 下列是一个响应示例
189
+ 当开启渲染缓存后,Modern.js 将通过响应头 `x-render-cache` 来标识当前请求的缓存状态。下面是一个响应示例:
200
190
 
201
191
  ```bash
202
192
  < HTTP/1.1 200 OK
@@ -209,11 +199,11 @@ export const cacheOption: CacheOption = {
209
199
  < Content-Length: 2937
210
200
  ```
211
201
 
212
- `x-render-cache` 可能会有以下几种值
202
+ `x-render-cache` 可能会有以下几种值:
213
203
 
214
204
  | 名称 | 说明 |
215
205
  | ------- | -------------------------------------------------- |
216
206
  | hit | 缓存命中,返回缓存内容 |
217
207
  | stale | 缓存命中,但数据陈旧,返回缓存内容的同时做重新渲染 |
218
208
  | expired | 缓存命中,重新渲染后返回渲染结果 |
219
- | miss | 缓存未命中 |
209
+ | miss | 缓存未命中 |