@modern-js/main-doc 2.6.0 → 2.8.0

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 (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
  :::