@modern-js/main-doc 2.6.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +2 -2
  4. package/en/apis/app/commands.mdx +2 -0
  5. package/en/apis/app/hooks/config/upload.mdx +10 -0
  6. package/en/apis/app/runtime/model/connect.mdx +1 -1
  7. package/en/apis/app/runtime/model/model_.mdx +1 -1
  8. package/en/apis/app/runtime/model/use-model.mdx +1 -1
  9. package/en/apis/app/runtime/web-server/hook.mdx +2 -2
  10. package/en/apis/app/runtime/web-server/middleware.mdx +33 -9
  11. package/en/components/enable-bff.mdx +4 -4
  12. package/en/components/init-rspack-app.mdx +7 -0
  13. package/en/configure/app/bff/enable-handle-web.mdx +24 -0
  14. package/en/configure/app/server/enable-framework-ext.mdx +1 -1
  15. package/en/configure/app/server/ssr.mdx +18 -0
  16. package/en/guides/advanced-features/bff/_category_.json +1 -1
  17. package/en/guides/advanced-features/eslint.mdx +30 -32
  18. package/en/guides/advanced-features/low-level.mdx +1 -1
  19. package/en/guides/advanced-features/rspack-start.mdx +13 -17
  20. package/en/guides/advanced-features/ssr.mdx +210 -5
  21. package/en/guides/advanced-features/web-server.mdx +87 -20
  22. package/en/guides/{css/tailwindcss.mdx → basic-features/css.mdx} +60 -3
  23. package/en/guides/basic-features/env-vars.mdx +4 -0
  24. package/en/guides/concept/builder.mdx +1 -1
  25. package/en/guides/topic-detail/framework-plugin/extend.mdx +20 -19
  26. package/en/guides/topic-detail/framework-plugin/hook-list.mdx +156 -155
  27. package/en/guides/topic-detail/framework-plugin/hook.mdx +58 -43
  28. package/en/guides/topic-detail/framework-plugin/implement.mdx +47 -49
  29. package/en/guides/topic-detail/framework-plugin/introduction.mdx +22 -23
  30. package/en/guides/topic-detail/framework-plugin/plugin-api.mdx +13 -13
  31. package/en/guides/topic-detail/framework-plugin/relationship.mdx +30 -30
  32. package/en/guides/topic-detail/generator/plugin/develop.mdx +1 -1
  33. package/en/guides/topic-detail/micro-frontend/c01-introduction.mdx +17 -17
  34. package/en/guides/topic-detail/micro-frontend/c02-development.mdx +76 -78
  35. package/en/guides/topic-detail/micro-frontend/c03-main-app.mdx +57 -51
  36. package/en/guides/topic-detail/micro-frontend/c04-communicate.mdx +11 -11
  37. package/en/guides/topic-detail/micro-frontend/c05-mixed-stack.mdx +13 -13
  38. package/en/guides/topic-detail/model/auto-actions.mdx +18 -21
  39. package/en/guides/topic-detail/model/computed-state.mdx +27 -25
  40. package/en/guides/topic-detail/model/define-model.mdx +14 -14
  41. package/en/guides/topic-detail/model/faq.mdx +12 -13
  42. package/en/guides/topic-detail/model/manage-effects.mdx +43 -52
  43. package/en/guides/topic-detail/model/model-communicate.mdx +47 -45
  44. package/en/guides/topic-detail/model/performance.mdx +22 -23
  45. package/en/guides/topic-detail/model/quick-start.mdx +29 -28
  46. package/en/guides/topic-detail/model/redux-integration.mdx +7 -7
  47. package/en/guides/topic-detail/model/test-model.mdx +11 -11
  48. package/en/guides/topic-detail/model/typescript-best-practice.mdx +16 -15
  49. package/en/guides/topic-detail/model/use-model.mdx +40 -45
  50. package/en/guides/topic-detail/model/use-out-of-modernjs.mdx +16 -16
  51. package/en/guides/troubleshooting/cli.mdx +2 -2
  52. package/en/tutorials/first-app/c03-css.mdx +1 -1
  53. package/package.json +5 -5
  54. package/zh/apis/app/commands.mdx +2 -0
  55. package/zh/apis/app/hooks/config/upload.mdx +12 -2
  56. package/zh/apis/app/runtime/model/connect.mdx +1 -1
  57. package/zh/apis/app/runtime/model/model_.mdx +1 -1
  58. package/zh/apis/app/runtime/model/use-model.mdx +1 -1
  59. package/zh/apis/app/runtime/web-server/hook.mdx +2 -4
  60. package/zh/apis/app/runtime/web-server/middleware.mdx +30 -10
  61. package/zh/apis/monorepo/commands/gen-release-note.mdx +3 -3
  62. package/zh/components/enable-bff.mdx +4 -4
  63. package/zh/components/init-rspack-app.mdx +7 -0
  64. package/zh/components/release-note.mdx +1 -1
  65. package/zh/configure/app/bff/enable-handle-web.mdx +24 -0
  66. package/zh/configure/app/server/enable-framework-ext.mdx +1 -1
  67. package/zh/configure/app/server/ssr.mdx +19 -1
  68. package/zh/guides/advanced-features/bff/_category_.json +1 -1
  69. package/zh/guides/advanced-features/rspack-start.mdx +13 -17
  70. package/zh/guides/advanced-features/ssr.mdx +210 -4
  71. package/zh/guides/advanced-features/web-server.mdx +81 -16
  72. package/zh/guides/{css/tailwindcss.mdx → basic-features/css.mdx} +60 -3
  73. package/zh/guides/basic-features/env-vars.mdx +4 -0
  74. package/zh/guides/concept/builder.mdx +1 -1
  75. package/zh/guides/topic-detail/changesets/github.mdx +2 -2
  76. package/zh/guides/topic-detail/changesets/release-note.mdx +1 -1
  77. package/zh/guides/topic-detail/framework-plugin/plugin-api.mdx +2 -2
  78. package/zh/guides/topic-detail/generator/plugin/develop.mdx +1 -1
  79. package/zh/guides/topic-detail/model/faq.mdx +1 -1
  80. package/zh/guides/topic-detail/model/manage-effects.mdx +1 -1
  81. package/zh/guides/topic-detail/model/model-communicate.mdx +1 -1
  82. package/zh/guides/topic-detail/model/performance.mdx +1 -1
  83. package/zh/guides/topic-detail/model/quick-start.mdx +2 -2
  84. package/zh/guides/topic-detail/model/use-model.mdx +3 -3
  85. package/zh/tutorials/first-app/c03-css.mdx +1 -1
  86. package/en/guides/css/_category_.json +0 -5
  87. package/en/guides/css/css-in-js.mdx +0 -40
  88. package/en/guides/css/css-modules.mdx +0 -87
  89. package/en/guides/css/less-sass.mdx +0 -17
  90. package/en/guides/css/postcss.mdx +0 -79
  91. package/zh/guides/css/_category_.json +0 -5
  92. package/zh/guides/css/css-in-js.mdx +0 -40
  93. package/zh/guides/css/css-modules.mdx +0 -87
  94. package/zh/guides/css/less-sass.mdx +0 -17
  95. package/zh/guides/css/postcss.mdx +0 -80
@@ -26,13 +26,23 @@ sidebar_position: 4
26
26
 
27
27
  ## 更多用法
28
28
 
29
- 不论是在[自定义 HTML](/guides/basic-features/html) 中,或是在 [`config/public/`](/apis/app/hooks/config/public) 下的任意 HTML 文件中,都可以直接使用 HTML 标签引用 `config/upload/` 目录下的资源:
29
+ 在 React 组件中,可以通过[内置环境变量](/guides/basic-features/env-vars.html#asset_prefix)来添加该前缀:
30
+
31
+ ```tsx
32
+ export default () => {
33
+ return (
34
+ <img src={`${process.env.ASSET_PREFIX}/upload/banner.png`}></img>
35
+ );
36
+ };
37
+ ```
38
+
39
+ 另外,不论是在[自定义 HTML](/guides/basic-features/html) 中,或是在 [`config/public/`](/apis/app/hooks/config/public) 下的任意 HTML 文件中,都可以直接使用 HTML 标签引用 `config/upload/` 目录下的资源:
30
40
 
31
41
  ```html
32
42
  <script src="/upload/index.js"></script>
33
43
  ```
34
44
 
35
- 如果设置了 [`output.assetPrefix`](/configure/app/output/asset-prefix) 前缀,也可以直接使用模板语法添加该前缀:
45
+ 如果设置了 [`dev.assetPrefix`](/configure/app/dev/asset-prefix) 或 [`output.assetPrefix`](/configure/app/output/asset-prefix) 前缀,也可以直接使用模板语法添加该前缀:
36
46
 
37
47
  ```html
38
48
  <script src="<%=assetPrefix %>/upload/index.js"></script>
@@ -9,7 +9,7 @@ import ReduckTip from "@site-docs/components/reduck-tip"
9
9
  <ReduckTip />
10
10
 
11
11
  :::tip 提示
12
- Reduck 原始类型较为复杂,以下涉及类型定义的地方,展示的是简化后的类型信息。原始类型见 [**connect**](https://github.com/modern-js-dev/reduck/blob/main/packages/react/src/connect.ts)。
12
+ Reduck 原始类型较为复杂,以下涉及类型定义的地方,展示的是简化后的类型信息。原始类型见 [**connect**](https://github.com/web-infra-dev/reduck/blob/main/packages/react/src/connect.ts)。
13
13
 
14
14
  :::
15
15
 
@@ -9,7 +9,7 @@ import ReduckTip from "@site-docs/components/reduck-tip"
9
9
  <ReduckTip />
10
10
 
11
11
  :::tip 提示
12
- Reduck 原始类型较为复杂,以下涉及类型定义的地方,展示的是简化后的类型信息。原始类型见 [**model**](https://github.com/modern-js-dev/reduck/blob/main/packages/store/src/model/model.ts)。
12
+ Reduck 原始类型较为复杂,以下涉及类型定义的地方,展示的是简化后的类型信息。原始类型见 [**model**](https://github.com/web-infra-dev/reduck/blob/main/packages/store/src/model/model.ts)。
13
13
 
14
14
  :::
15
15
 
@@ -9,7 +9,7 @@ import ReduckTip from "@site-docs/components/reduck-tip"
9
9
  <ReduckTip />
10
10
 
11
11
  :::tip 提示
12
- Reduck 原始类型较为复杂,以下涉及类型定义的地方,展示的是简化后的类型信息。原始类型见 [model](https://github.com/modern-js-dev/reduck/blob/main/packages/store/src/model/useModel.ts)。
12
+ Reduck 原始类型较为复杂,以下涉及类型定义的地方,展示的是简化后的类型信息。原始类型见 [model](https://github.com/web-infra-dev/reduck/blob/main/packages/store/src/model/useModel.ts)。
13
13
 
14
14
  :::
15
15
 
@@ -3,11 +3,10 @@ title: Hook
3
3
  ---
4
4
  # Hook
5
5
 
6
- 用于拓展 Modern.js 内置的 Web Server,非 BFF 请求会经过这些中 Hook 的处理。
6
+ 用于拓展 Modern.js 内置的 Web Server,所有的页面请求都会经过 Hook
7
7
 
8
8
  :::note
9
9
  更多内容可以查看[自定义 Web Server](/guides/advanced-features/web-server)。
10
-
11
10
  :::
12
11
 
13
12
  ## 使用姿势
@@ -27,7 +26,6 @@ pnpm run new
27
26
  ? 请选择你想要的操作 创建工程元素
28
27
  ? 新建「自定义 Web Server」源码目录
29
28
  ```
30
-
31
29
  :::
32
30
 
33
31
  ## 函数签名
@@ -64,7 +62,7 @@ type HookContext = {
64
62
  function Hook(context: HookContext, next: NextFunction): Promsie<void> | void;
65
63
  ```
66
64
 
67
- 另外,不同 Hook 额外提供了不同的上下文。目前 Modern.js 支持 `AtferMatch` 和 `AfterRender` 两个 Hook。
65
+ 另外,不同 Hook 额外提供了不同的上下文。目前 Modern.js 支持 `AfterMatch` 和 `AfterRender` 两个 Hook。
68
66
 
69
67
  ```ts
70
68
  type AfterMatchContext = HookContext & {
@@ -3,13 +3,10 @@ title: Middleware
3
3
  ---
4
4
  # Middleware
5
5
 
6
- 用于拓展 Modern.js 内置的 Web Server,只有 SSR 请求会经过这些中间件。
7
-
8
- 与 [Hook](/apis/app/runtime/web-server/hook) 不同的是,Middleware 可以使用 Server 运行时框架拓展。
6
+ 用于拓展 Modern.js 内置的 Web Server,与 [Hook](/apis/app/runtime/web-server/hook) 不同的是,Middleware 可以直接操作 Node 原生的请求、响应对象,并且可以使用框架拓展。
9
7
 
10
8
  :::note
11
9
  更多内容可以查看[自定义 Web Server](/guides/advanced-features/web-server)。
12
-
13
10
  :::
14
11
 
15
12
  ## 使用姿势
@@ -38,6 +35,11 @@ pnpm run new
38
35
  ## 函数签名
39
36
 
40
37
  ```ts
38
+ type Middleware = (
39
+ context: MiddlewareContext,
40
+ next: NextFunction,
41
+ ) => Promise<void> | void;
42
+
41
43
  type MiddlewareContext = {
42
44
  response: {
43
45
  set: (key: string, value: string) => void;
@@ -71,11 +73,6 @@ type MiddlewareContext = {
71
73
  res: ServerResponse;
72
74
  };
73
75
  };
74
-
75
- type RequestHandler = (
76
- context: Context,
77
- next: NextFunction,
78
- ) => Promise<void> | void;
79
76
  ```
80
77
 
81
78
  ### 参数
@@ -86,6 +83,10 @@ type RequestHandler = (
86
83
  - `source`:提供 Node.js 原生的 `req` 与 `res` 对象。
87
84
  - `next`:执行当前 Hook 的下一个监听函数(不影响整体服务端流程)。
88
85
 
86
+ :::warning
87
+ `next` 函数的执行不影响后续内置流程,只控制下一个中间件是否执行。只有当响应被写入时,后续渲染流程才会中断。
88
+ :::
89
+
89
90
  ## 示例
90
91
 
91
92
  ### 服务端耗时打点
@@ -107,5 +108,24 @@ Modern.js 提供了 `res.locals` 属性用来存放当前请求的局部变量
107
108
  export const Middleware = () => async (ctx, next) => {
108
109
  ctx.res.locals.id = 'Modern.js';
109
110
  ctx.res.locals.rpc = createRpcInstance();
110
- });
111
+ };
111
112
  ```
113
+
114
+ ### 框架拓展
115
+
116
+ Middleware 还可以和 BFF 一样,使用运行时框架拓展。Modern.js 约定,当使用框架运行时拓展时,类型信息从 `@modern-js/runtime/{namespace}` 下导出,Middleware 可以使用框架语法,例如框架中间件写法,以下是伪代码:
117
+
118
+ ```ts
119
+ import { SomeType } from '@modern-js/runtime/{namespace}';
120
+
121
+ export const middleware: SomeType = (ctx, next) => {
122
+ console.log(ctx.url);
123
+ next();
124
+ };
125
+ ```
126
+
127
+ 默认情况下,在安装框架拓展插件后,Web Server 的框架拓展能力是关闭的。如果希望使用框架拓展,可以通过 [`server.enableFrameworkExt`](/configure/app/server/enable-framework-ext.html) 开启。
128
+
129
+ :::info
130
+ 框架拓展导出的类型名不一定为 Middleware,命名由框架拓展插件。
131
+ :::
@@ -9,7 +9,7 @@ Usage: modern gen-release-note [options]
9
9
  根据当前仓库 changeset 文件生成 Release Note
10
10
 
11
11
  Options:
12
- --repo <repo> 仓库名称,用于生成 Pull Request 链接, 例如: modern-js-dev/modern.js
12
+ --repo <repo> 仓库名称,用于生成 Pull Request 链接, 例如: web-infra-dev/modern.js
13
13
  --custom <cumtom> 自定义 Release Note 生成函数
14
14
  -h, --help display help for command
15
15
  ```
@@ -24,9 +24,9 @@ Options:
24
24
  ```markdown
25
25
  ## Features:
26
26
 
27
- [[#1160](https://github.com/modern-js-dev/modern.js/pull/1160)] export ExecaError type
27
+ [[#1160](https://github.com/web-infra-dev/modern.js/pull/1160)] export ExecaError type
28
28
 
29
29
  ## Bug Fix:
30
30
 
31
- [[#1264](https://github.com/modern-js-dev/modern.js/pull/1264)] fix: conventional router app use App.init not work
31
+ [[#1264](https://github.com/web-infra-dev/modern.js/pull/1264)] fix: conventional router app use App.init not work
32
32
  ```
@@ -7,8 +7,8 @@ import { Tabs, Tab as TabItem } from "@theme";
7
7
  <TabItem value="express" label="Express.js" default>
8
8
 
9
9
  ```ts title="edenx.config.ts"
10
- import expressPlugin from '@edenx/plugin-express';
11
- import bffPlugin from '@edenx/plugin-bff';
10
+ import expressPlugin from '@modern-js/plugin-express';
11
+ import bffPlugin from '@modern-js/plugin-bff';
12
12
 
13
13
  export default defineConfig({
14
14
  plugins: [expressPlugin(), bffPlugin()],
@@ -19,8 +19,8 @@ export default defineConfig({
19
19
  <TabItem value="koa" label="Koa.js">
20
20
 
21
21
  ```ts title="edenx.config.ts"
22
- import koaPlugin from '@edenx/plugin-koa';
23
- import bffPlugin from '@edenx/plugin-bff';
22
+ import koaPlugin from '@modern-js/plugin-koa';
23
+ import bffPlugin from '@modern-js/plugin-bff';
24
24
 
25
25
  export default defineConfig({
26
26
  plugins: [koaPlugin(), bffPlugin()],
@@ -0,0 +1,7 @@
1
+ ```bash
2
+ $ npx @modern-js/create myapp
3
+ ? 请选择你想创建的工程类型 应用
4
+ ? 请选择开发语言 TS
5
+ ? 请选择包管理工具 pnpm
6
+ ? 请选择构建工具 Rspack
7
+ ```
@@ -1 +1 @@
1
- 根据官网 [Release Note](https://github.com/modern-js-dev/modern.js/releases),开发者也可以手动将项目升级到想要的版本。
1
+ 根据官网 [Release Note](https://github.com/web-infra-dev/modern.js/releases),开发者也可以手动将项目升级到想要的版本。
@@ -0,0 +1,24 @@
1
+ ---
2
+ title: enableHandleWeb
3
+ ---
4
+
5
+ # bff.enableHandleWeb
6
+
7
+ - **类型:** `boolean`
8
+ - **默认值:** `false`
9
+
10
+ :::caution 注意
11
+ 请先在当前应用项目根目录使用【[new](/apis/app/commands#modern-new)】 启用 BFF 功能。
12
+ :::
13
+
14
+ 默认情况下,BFF 服务只能处理 BFF API 的请求。
15
+
16
+ 当该值设置为 `true` 时,页面请求流量也会经过 BFF,并且 Modern.js 内置的页面渲染的逻辑默认会作为 BFF 服务的最后一个中间件运行。
17
+
18
+ ```ts title="modern.config.ts"
19
+ export default defineConfig({
20
+ bff: {
21
+ enableHandleWeb: true,
22
+ },
23
+ });
24
+ ```
@@ -35,7 +35,7 @@ export const middleware: Middleware = (ctx, next) => {
35
35
  开启后,Middleware 类型将从其他命名空间下导出,并且可以使用框架拓展的语法:
36
36
 
37
37
  ```ts title="server/index.ts"
38
- import { SomeType } from '@modern-js/runtime/{frameworknName}';
38
+ import { SomeType } from '@modern-js/runtime/{namespace}';
39
39
 
40
40
  export const middleware: SomeType = (...args) => {
41
41
  console.log(args[0].url);
@@ -4,11 +4,13 @@ sidebar_label: ssr
4
4
 
5
5
  # server.ssr
6
6
 
7
- - **类型:** `boolean`
7
+ - **类型:** `boolean` | `Object`
8
8
  - **默认值:** `false`
9
9
 
10
10
  SSR 开关以及相关设置。
11
11
 
12
+ ### Boolean 类型
13
+
12
14
  当值类型为 `boolean` 时,表示是否开启 SSR 部署模式,默认 `false` 不开启。
13
15
 
14
16
  ```ts title="modern.config.ts"
@@ -18,3 +20,19 @@ export default defineConfig({
18
20
  },
19
21
  });
20
22
  ```
23
+
24
+ ### Object 类型
25
+
26
+ 当值类型为 `Object` 时,可以配置如下属性:
27
+
28
+ - `mode`:`string = 'string'`,默认为使用 `renderToString` 渲染。配置为 'stream' 开启流式渲染。
29
+ - `forceCSR`:`boolean = false`,默认关闭强制 CSR 渲染。配置为 `true` 后,在页面访问时添加 `?csr=true` 即可强制 CSR。
30
+
31
+ ```ts title="modern.config.ts"
32
+ export default defineConfig({
33
+ server: {
34
+ forceCSR: true,
35
+ mode: 'stream',
36
+ },
37
+ });
38
+ ```
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "label": "BFF",
3
- "position": 1,
3
+ "position": 2,
4
4
  "link": {
5
5
  "type": "doc",
6
6
  "id": "guides/advanced-features/bff/index"
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: 使用 Rspack
3
- sidebar_position: 12
3
+ sidebar_position: 1
4
4
  ---
5
5
 
6
6
  # 使用 Rspack
7
7
 
8
- [Rspack](https://www.rspack.org/) 是字节跳动 Web Infra 团队自研的 Rust Bundler,核心架构对齐 webpack 实现,并对社区常用的构建能力做了开箱即用的支持。
8
+ [Rspack](https://www.rspack.dev/) 是字节跳动 Web Infra 团队自研的 Rust Bundler,核心架构对齐 webpack 实现,并对社区常用的构建能力做了开箱即用的支持。
9
9
 
10
10
  Rspack 通过以下方式来提升编译性能:
11
11
 
@@ -13,22 +13,18 @@ Rspack 通过以下方式来提升编译性能:
13
13
  - 充分利用多核优势,整个编译过程充分进行多线程优化。
14
14
  - 基于请求的按需编译(Lazy Compilation),减小每次编译的模块数目,以提升冷启动的速度。
15
15
 
16
- ## 初始化 rspack 项目
16
+ ## 初始化 Rspack 项目
17
17
 
18
- Modern.js 生成器会提供一个可交互的问答界面,只需将构建工具选择为**rspack**,即可创建一个 rspack 项目:
18
+ Modern.js 生成器会提供一个可交互的问答界面,只需将构建工具选择为 **Rspack**,即可创建一个 Rspack 项目:
19
19
 
20
- ```bash
21
- $ npx @modern-js/create myapp
22
- ? 请选择你想创建的工程类型 应用
23
- ? 请选择开发语言 TS
24
- ? 请选择包管理工具 pnpm
25
- ? 请选择构建工具 rspack
26
- ```
20
+ import InitRspackApp from "@site-docs/components/init-rspack-app"
21
+
22
+ <InitRspackApp />
27
23
 
28
24
  项目创建完成后,在项目中执行 `pnpm run dev` 即可体验项目。更多项目信息可参考[快速上手](/guides/get-started/quick-start.html)。
29
25
 
30
26
  :::tip
31
- 使用 rspack 作为打包工具时,以下功能暂不支持使用:
27
+ 使用 Rspack 作为打包工具时,以下功能暂不支持使用:
32
28
 
33
29
  - 服务端渲染(SSR)
34
30
  - 静态站点生成(SSG)
@@ -37,17 +33,17 @@ $ npx @modern-js/create myapp
37
33
 
38
34
  :::
39
35
 
40
- ## 从 webpack 迁移至 rspack
36
+ ## 从 webpack 迁移至 Rspack
41
37
 
42
- 通过执行 `pnpm run new` 可启用 rspack 构建:
38
+ 通过执行 `pnpm run new` 可启用 Rspack 构建:
43
39
 
44
40
  ```bash
45
41
  $ pnpm run new
46
42
  ? 请选择你想要的操作 启用可选功能
47
- ? 启用可选功能 启用「rspack 构建」
43
+ ? 启用可选功能 启用「Rspack 构建」
48
44
  ```
49
45
 
50
- 执行命令后,在 modern.config.ts 中开启 rspack 构建:
46
+ 执行命令后,在 modern.config.ts 中开启 Rspack 构建:
51
47
 
52
48
  ```ts title=modern.config.ts
53
49
  import appTools, { defineConfig } from '@modern-js/app-tools';
@@ -65,5 +61,5 @@ export default defineConfig<'rspack'>({
65
61
  ```
66
62
 
67
63
  :::tip
68
- 从 webpack 迁移至 rspack,会有一些构建和配置能力上的差异,详情可参考:[配置差异](https://modernjs.dev/builder/guide/advanced/rspack-start.html#从-webpack-迁移到-rspack)
64
+ 从 webpack 迁移至 Rspack,会有一些构建和配置能力上的差异,详情可参考:[配置差异](https://modernjs.dev/builder/guide/advanced/rspack-start.html#从-webpack-迁移到-rspack)
69
65
  :::
@@ -43,10 +43,13 @@ Modern.js 打破传统的 SSR 开发模式,提供了用户无感的 SSR 开发
43
43
  不过,开发者仍然需要关注数据的兜底处理,例如 `null` 值或不符合预期的数据返回。避免在 SSR 时产生 React 渲染错误或是返回凌乱的渲染结果。
44
44
 
45
45
  :::info 补充信息
46
- 使用 Data Loader 时,数据获取发生在渲染前,Modern.js 也仍然支持在组件渲染时获取数据。更多相关内容可以查看[数据获取](/guides/basic-features/data-fetch)。
46
+ 1. 当以客户端路由的方式请求页面时,Modern.js 会发送一个 HTTP 请求,服务端接收到请求后执行页面对应的 Data Loader 函数,然后将执行结果作为请求的响应返回浏览器。
47
47
 
48
+ 2. 使用 Data Loader 时,数据获取发生在渲染前,Modern.js 也仍然支持在组件渲染时获取数据。更多相关内容可以查看[数据获取](/guides/basic-features/data-fetch)。
48
49
  :::
49
50
 
51
+
52
+
50
53
  ## 保持渲染一致
51
54
 
52
55
  有些业务中,通常需要根据当前的运行容器环境特征做不同的 UI 展示,例如 [UA](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) 信息。如果处理不够仔细,此时很有可能出现不符合预期的渲染结果。
@@ -277,7 +280,7 @@ export const loader = () => {
277
280
 
278
281
  ## 流式渲染
279
282
 
280
- Modern.js 支持了 React 18 的流式渲染,可以通过如下配置修改默认的渲染模式:
283
+ Modern.js 支持了 React 18 的流式渲染,可以通过如下配置启用:
281
284
 
282
285
  ```json
283
286
  {
@@ -289,7 +292,210 @@ Modern.js 支持了 React 18 的流式渲染,可以通过如下配置修改默
289
292
  }
290
293
  ```
291
294
 
292
- :::note
293
- 目前 Modern.js 内置的数据获取方式还未支持流式渲染,如迫切需要开发者可以按照 React Stream SSR 的 Demo 自建。
295
+ Modern.js 的流式渲染基于 React Router 实现,主要涉及 API 有:
296
+
297
+ - [`defer`](https://reactrouter.com/en/main/utils/defer):在 Data Loader 中使用,用于支持异步获取数据。
298
+ - [`Await`](https://reactrouter.com/en/main/components/await):用于渲染 Data Loader 返回的异步数据。
299
+ - [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value):用于从最近的父级 `Await` 组件中获取数据。
300
+
301
+
302
+ ### 异步获取数据
303
+
304
+ ```ts title='page.loader.ts'
305
+ import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
306
+
307
+ interface User {
308
+ name: string;
309
+ age: number;
310
+ }
311
+
312
+ export interface Data {
313
+ data: User;
314
+ }
315
+
316
+ export default ({ params }: LoaderFunctionArgs) => {
317
+ const userId = params.id;
318
+
319
+ const user = new Promise<User>(resolve => {
320
+ setTimeout(() => {
321
+ resolve({
322
+ name: `user-${userId}`,
323
+ age: 18,
324
+ });
325
+ }, 200);
326
+ });
327
+
328
+ return defer({ data: user });
329
+ };
330
+
331
+ ```
332
+
333
+ `user` 是一个 Promise 类型的对象,表示需要异步获取的数据,通过 `defer` 处理需要异步获取的 `user`。注意,`defer` 必须接收一个对象类型的参数,
334
+ 因此, 传入 `defer` 的参数为 `{data: user}`。
335
+
336
+ `defer` 还可以同时接收异步数据和同步数据。例如:
337
+
338
+ ```ts title='page.loader.ts'
339
+
340
+ // 省略部分代码
341
+
342
+ export default ({ params }: LoaderFunctionArgs) => {
343
+ const userId = params.id;
344
+
345
+ const user = new Promise<User>(resolve => {
346
+ setTimeout(() => {
347
+ resolve({
348
+ name: `user-${userId}`,
349
+ age: 18,
350
+ });
351
+ }, 200);
352
+ });
353
+
354
+ const otherData = new Promise<string>(resolve => {
355
+ setTimeout(() => {
356
+ resolve('some sync data');
357
+ }, 200);
358
+ });
359
+
360
+ return defer({
361
+ data: user,
362
+ other: await otherData
363
+ });
364
+ };
365
+
366
+ ```
367
+
368
+ `otherData` 前加了 `await`,所以是同步获取的数据,它可以和异步获取的数据 `user` 同时传入 `defer`。
369
+
370
+
371
+ ### 渲染异步数据
372
+
373
+ 通过 `Await` 组件,可以获取到 Data Loader 中异步返回的数据,然后进行渲染。例如:
374
+
375
+ ```ts title='page.tsx'
376
+ import { Await, useLoaderData } from '@modern-js/runtime/router';
377
+ import { Suspense } from 'react';
378
+ import type { Data } from './page.loader';
379
+
380
+ const Page = () => {
381
+ const data = useLoaderData() as Data;
382
+
383
+ return (
384
+ <div>
385
+ User info:
386
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
387
+ <Await resolve={data.data}>
388
+ {(user) => {
389
+ return (
390
+ <div id="data">
391
+ name: {user.name}, age: {user.age}
392
+ </div>
393
+ );
394
+ }}
395
+ </Await>
396
+ </Suspense>
397
+ </div>
398
+ );
399
+ };
294
400
 
401
+ export default Page;
402
+ ```
403
+
404
+ `Await` 需要包裹在 `Suspense` 组件内部,`Await` 的 `resolve` 传入的是 Data Loader 异步获取的数据,当数据获取完成后,
405
+ 通过 [Render Props](https://reactjs.org/docs/render-props.html) 模式,渲染获取到的数据。在数据的获取阶段,将展示
406
+ `Suspense` 组件 `fallback` 属性设置的内容。
407
+
408
+ :::warning 注意
409
+ 从 Data Loader 文件导入类型时,需要使用 import type 语法,保证只导入类型信息,这样可以避免 Data Loader 的代码打包到前端产物的 bundle 文件中。
410
+
411
+ 所以,这里的导入方式为:`import type { Data } from './page.loader'`;
412
+ :::
413
+
414
+ 也可以通过 `useAsyncValue` 获取 Data Loader 返回的异步数据。例如:
415
+
416
+ ```
417
+ ```ts title='page.tsx'
418
+ import { useAsyncValue } from '@modern-js/runtime/router';
419
+
420
+ // 省略部分代码
421
+
422
+ const UserInfo = () => {
423
+ const user = useAsyncValue();
424
+
425
+ return (
426
+ <div>
427
+ name: {user.name}, age: {user.age}
428
+ </div>
429
+ )
430
+ }
431
+
432
+ const Page = () => {
433
+ const data = useLoaderData() as Data;
434
+
435
+ return (
436
+ <div>
437
+ User info:
438
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
439
+ <Await resolve={data.data}>
440
+ <UserInfo />
441
+ </Await>
442
+ </Suspense>
443
+ </div>
444
+ );
445
+ };
446
+
447
+ export default Page;
448
+ ```
449
+
450
+ ### 错误处理
451
+
452
+ `Await` 组件的 `errorElement` 属性,可以用来处理当 Data Loader 执行时,或者子组件渲染时抛出的错误。
453
+ 例如,我们故意在 Data Loader 函数中抛出错误:
454
+
455
+ ```ts title='page.loader.ts'
456
+ import { defer } from '@modern-js/runtime/router';
457
+
458
+ export default () => {
459
+ const data = new Promise((resolve, reject) => {
460
+ setTimeout(() => {
461
+ reject(new Error('error occurs'));
462
+ }, 200);
463
+ });
464
+
465
+ return defer({ data });
466
+ };
467
+ ```
468
+
469
+ 然后通过 `useAsyncError` 获取错误,并将用于渲染错误信息的组件赋值给 `Await` 组件的 `errorElement` 属性:
470
+
471
+ ```ts title='page.ts'
472
+ import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
473
+ import { Suspense } from 'react';
474
+
475
+ export default function Page() {
476
+ const data = useLoaderData();
477
+
478
+ return (
479
+ <div>
480
+ Error page
481
+ <Suspense fallback={<div>loading ...</div>}>
482
+ <Await resolve={data.data} errorElement={<ErrorElement />}>
483
+ {(data: any) => {
484
+ return <div>never displayed</div>;
485
+ }}
486
+ </Await>
487
+ </Suspense>
488
+ </div>
489
+ );
490
+ }
491
+
492
+ function ErrorElement() {
493
+ const error = useAsyncError() as Error;
494
+ return <p>Something went wrong! {error.message}</p>;
495
+ }
496
+ ```
497
+
498
+ :::info 补充信息
499
+ 1. [Deferred Data](https://reactrouter.com/en/main/guides/deferred)
500
+ 2. [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37)
295
501
  :::