@modern-js/main-doc 2.0.0-canary.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/_category_.json +1 -1
  3. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/core/use-module-apps.md +62 -31
  4. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/router/router.md +174 -375
  5. package/en/docusaurus-plugin-content-docs/current/components/enable-bff.md +36 -0
  6. package/en/docusaurus-plugin-content-docs/current/components/enable-micro-frontend.md +13 -0
  7. package/en/docusaurus-plugin-content-docs/current/components/micro-master-manifest-config.md +15 -0
  8. package/en/docusaurus-plugin-content-docs/current/components/micro-runtime-config.md +18 -0
  9. package/en/docusaurus-plugin-content-docs/current/components/router-legacy-tip.md +1 -0
  10. package/en/docusaurus-plugin-content-docs/current/configure/app/auto-load-plugin.md +62 -0
  11. package/en/docusaurus-plugin-content-docs/current/configure/app/deploy/microFrontend.md +54 -0
  12. package/en/docusaurus-plugin-content-docs/current/configure/app/output/ssg.md +226 -0
  13. package/en/docusaurus-plugin-content-docs/current/configure/app/runtime/master-app.md +20 -39
  14. package/en/docusaurus-plugin-content-docs/current/configure/app/runtime/router.md +17 -4
  15. package/en/docusaurus-plugin-content-docs/current/configure/app/runtime/state.md +17 -4
  16. package/en/docusaurus-plugin-content-docs/current/configure/app/server/enable-framework-ext.md +47 -0
  17. package/en/docusaurus-plugin-content-docs/current/guides/advanced-features/bff/frameworks.md +2 -0
  18. package/en/docusaurus-plugin-content-docs/current/guides/advanced-features/bff/function.md +10 -6
  19. package/en/docusaurus-plugin-content-docs/current/guides/advanced-features/ssg.md +6 -2
  20. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/css/_category_.json +4 -0
  21. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/data-fetch.md +1 -1
  22. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/routes.md +0 -2
  23. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/_category_.json +5 -0
  24. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/extend.md +162 -0
  25. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/hook-list.md +803 -0
  26. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/hook.md +169 -0
  27. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/implement.md +247 -0
  28. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/introduction.md +49 -0
  29. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/plugin-api.md +116 -0
  30. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/relationship.md +118 -0
  31. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/generator/config/common.md +1 -1
  32. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/generator/config/module.md +3 -1
  33. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/generator/config/mwa.md +1 -9
  34. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/generator/project.md +2 -2
  35. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/micro-frontend/_category_.json +4 -0
  36. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/micro-frontend/c01-introduction.md +29 -0
  37. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/micro-frontend/c02-development.md +191 -0
  38. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/micro-frontend/c03-main-app.md +246 -0
  39. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/micro-frontend/c04-communicate.md +54 -0
  40. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/micro-frontend/c05-mixed-stack.md +24 -0
  41. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/_category_.json +4 -0
  42. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/auto-actions.md +90 -0
  43. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/computed-state.md +151 -0
  44. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/define-model.md +66 -0
  45. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/faq.md +43 -0
  46. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/manage-effects.md +259 -0
  47. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/model-communicate.md +219 -0
  48. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/performance.md +173 -0
  49. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/quick-start.md +116 -0
  50. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/redux-integration.md +21 -0
  51. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/test-model.md +43 -0
  52. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/typescript-best-practice.md +71 -0
  53. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/use-model.md +244 -0
  54. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/model/use-out-of-modernjs.md +51 -0
  55. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/_category_.json +5 -0
  56. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c01-start.md +99 -0
  57. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c02-component.md +56 -0
  58. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c03-css.md +324 -0
  59. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c04-routes.md +169 -0
  60. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c05-loader.md +82 -0
  61. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c06-model.md +260 -0
  62. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c07-container.md +283 -0
  63. package/en/docusaurus-plugin-content-docs/current/tutorials/first-app/c08-entries.md +137 -0
  64. package/en/docusaurus-plugin-content-docs/current/tutorials/foundations/_category_.json +1 -1
  65. package/en/docusaurus-plugin-content-docs/current/tutorials/foundations/introduction.md +5 -3
  66. package/package.json +4 -4
  67. package/zh/apis/app/runtime/core/use-module-apps.md +2 -0
  68. package/zh/apis/app/runtime/router/router.md +169 -371
  69. package/zh/components/enable-bff.md +36 -0
  70. package/zh/components/micro-master-manifest-config.md +15 -0
  71. package/zh/components/router-legacy-tip.md +1 -0
  72. package/zh/configure/app/auto-load-plugin.md +62 -0
  73. package/zh/configure/app/deploy/microFrontend.md +0 -10
  74. package/zh/configure/app/output/ssg.md +1 -5
  75. package/zh/configure/app/runtime/master-app.md +4 -18
  76. package/zh/configure/app/runtime/router.md +19 -4
  77. package/zh/configure/app/runtime/state.md +7 -7
  78. package/zh/configure/app/server/enable-framework-ext.md +47 -0
  79. package/zh/configure/app/server/port.md +1 -1
  80. package/zh/configure/app/tools/_category_.json +1 -1
  81. package/zh/guides/advanced-features/bff/frameworks.md +2 -0
  82. package/zh/guides/advanced-features/bff/function.md +7 -5
  83. package/zh/guides/advanced-features/eslint.md +2 -1
  84. package/zh/guides/advanced-features/ssg.md +4 -0
  85. package/zh/guides/basic-features/data-fetch.md +1 -1
  86. package/zh/guides/basic-features/env-vars.md +1 -1
  87. package/zh/guides/basic-features/routes.md +0 -3
  88. package/zh/guides/topic-detail/generator/config/module.md +3 -1
  89. package/zh/guides/topic-detail/generator/config/mwa.md +1 -9
  90. package/zh/guides/topic-detail/model/quick-start.md +1 -1
  91. package/zh/tutorials/first-app/c06-model.md +5 -1
  92. package/zh/tutorials/first-app/c08-entries.md +1 -1
  93. package/zh/tutorials/foundations/introduction.md +5 -3
  94. package/en/docusaurus-plugin-content-docs/current/apis/app/overview.md +0 -12
  95. package/en/docusaurus-plugin-content-docs/current/configure/app/bff/fetcher.md +0 -28
  96. package/en/docusaurus-plugin-content-docs/current/configure/app/dev/with-master-app.md +0 -31
  97. package/en/docusaurus-plugin-content-docs/current/guides/overview.md +0 -11
  98. package/en/docusaurus-plugin-content-docs/current/tutorials/foundations/basic.md +0 -8
  99. package/zh/apis/app/overview.md +0 -11
  100. package/zh/apis/monorepo/overview.md +0 -11
  101. package/zh/configure/app/bff/fetcher.md +0 -31
  102. package/zh/configure/app/dev/with-master-app.md +0 -32
  103. package/zh/guides/overview.md +0 -11
  104. package/zh/tutorials/foundations/basic.md +0 -8
@@ -0,0 +1,244 @@
1
+ ---
2
+ sidebar_position: 3
3
+ title: 使用 Model
4
+ ---
5
+
6
+ ## 在组件内使用
7
+ ### 作为全局状态使用
8
+
9
+ 通过 `useModel` 可以获取 Model 的 State、Actions 等。当 Model 的 State 通过 Actions 进行修改后,任何其他使用了该 Model 的组件,都会自动重新渲染。
10
+
11
+ 在 [快速上手](/docs/guides/topic-detail/model/quick-start) 的计数器案例中,我们已经演示了 `useModel` 的使用,不再重复。
12
+
13
+ `useModel` 支持传入多个 Model,多个 Model 的 State 和 Actions 会进行合并后作为返回结果。例如:
14
+
15
+ ```ts
16
+ const fooModel = model('foo').define({
17
+ state: {
18
+ value: 1,
19
+ },
20
+ actions: {
21
+ add(state) {
22
+ state += 1;
23
+ },
24
+ },
25
+ });
26
+
27
+ const barModel = model('bar').define({
28
+ state: {
29
+ title: 'bar',
30
+ },
31
+ actions: {
32
+ set(state, payload) {
33
+ state.title = payload;
34
+ },
35
+ },
36
+ });
37
+
38
+ const [state, actions] = useModel([fooModel, barModel]);
39
+ // 或
40
+ const [state, actions] = useModel(fooModel, barModel);
41
+ ```
42
+
43
+ `state` 和 `actions` 的值分别为:
44
+
45
+ ```ts
46
+ state = {
47
+ value: 1,
48
+ title: 'bar',
49
+ };
50
+
51
+ actions = {
52
+ add(state) {
53
+ state += 1;
54
+ },
55
+ set(state, payload) {
56
+ state.title = payload;
57
+ },
58
+ };
59
+ ```
60
+
61
+ `useModel` 还支持对 State 和 Actions 做 selector 操作,实现对 State 和 Actions 的筛选或重命名,例如:
62
+
63
+
64
+ ```ts
65
+ const fooModel = model('foo').define({
66
+ state: {
67
+ value: 1,
68
+ },
69
+ actions: {
70
+ add(state) {
71
+ state += 1;
72
+ },
73
+ },
74
+ });
75
+
76
+ const barModel = model('bar').define({
77
+ state: {
78
+ value: 'bar',
79
+ },
80
+ actions: {
81
+ set(state, payload) {
82
+ state.value = payload;
83
+ },
84
+ },
85
+ });
86
+
87
+ const [state, actions] = useModel(
88
+ [fooModel, barModel],
89
+ (fooState, barState) => ({
90
+ fooValue: fooState.value,
91
+ barValue: barState.value,
92
+ }), // stateSelector
93
+ (fooActions, barActions) => ({ add: fooActions.add }), // actionsSelector
94
+ );
95
+ ```
96
+
97
+ 我们通过 `stateSelector` ,把 `fooModel` 和 `barModel` 中重名的状态做了命名修改,通过 `actionsSelector` ,过滤掉了 `barModel` 的 Actions。
98
+
99
+ 如果只需要设置 `actionsSelector`,可以把 `stateSelector` 设置为 `undefined`,作为参数占位。例如:
100
+
101
+ ```ts
102
+ const [state, actions] = useModel(
103
+ [fooModel, barModel],
104
+ undefined,
105
+ (fooActions, barActions) => ({ add: fooActions.add }), // actionsSelector
106
+ );
107
+ ```
108
+
109
+ ### 作为静态状态使用
110
+
111
+ 通过 `useStaticModel` 获取 Model ,将 Model 中的状态作为静态状态使用。可以保证组件每次访问到的 Model 的 State 都是最新值,但是 Model 的 State 的变化,并不会引起当前组件的重新渲染。
112
+
113
+ :::info 注
114
+ `useStaticModel` 的使用方式和 `useModel` 完全一致。
115
+ :::
116
+
117
+ 考虑下面一种场景,有一个组件 Input 负责用户输入,另外一个组件 Search 负责根据用户的输入信息,在点击查询按钮后执行查询操作,我们不希望用户输入过程中的状态变化引起 Search 重新渲染,这时候就可以使用 `useStaticModel`:
118
+
119
+ ```ts
120
+ import { useStaticModel } from '@modern-js/runtime/model';
121
+
122
+ function Search() {
123
+ // 这里注意不要解构 state
124
+ const [state] = useStaticModel(searchModel);
125
+
126
+ return (
127
+ <div>
128
+ <button
129
+ onClick={async () => {
130
+ const result = await mockSearch(state.input);
131
+ console.log(result);
132
+ }}
133
+ >
134
+ Search
135
+ </button>
136
+ </div>
137
+ );
138
+ }
139
+ ```
140
+
141
+ :::warning 注意
142
+ 不要解构 `useStaticModel` 返回的 `state`,例如改成如下写法:
143
+ `const [{input}] = useStaticModel(searchModel);`
144
+ 将始终获取到 Input 的初始值。
145
+ :::
146
+
147
+ `useStaticModel` 还适合和 [react-three-fiber](https://github.com/pmndrs/react-three-fiber) 等动画库一起使用,因为在动画组件 UI 里绑定会快速变化的状态,容易引起[性能问题](https:/docs.pmnd.rs/react-three-fiber/advanced/pitfalls#never-bind-fast-state-reactive)。这种情况就可以选择使用 `useStaticModel`,它只会订阅状态,但不会引起视图组件的重新渲染。下面是一个简化示例:
148
+
149
+ ```ts
150
+ function ThreeComponent() {
151
+ const [state, actions] = useStaticModel(modelA);
152
+
153
+ useFrame(() => {
154
+ state.value; // 假设初始化为 0
155
+ actions.setValue(1);
156
+ state.value; // 这里会得到1
157
+ });
158
+ }
159
+ ```
160
+
161
+ 使用 React 的 refs 也可以实现类似效果,其实 `useStaticModel` 内部也使用到了 refs。不过直接 `useStaticModel` 有助于将状态的管理逻辑从组件中解耦,统一收敛到 Model 层。
162
+
163
+ 完整的示例代码可以在[这里](https://github.com/modern-js-dev/modern-js-examples/tree/main/series/tutorials/runtime-api/model/static-model)查看。
164
+
165
+ ### 作为局部状态使用
166
+
167
+ 通过 `useLocalModel` 获取 Model ,将 Model 中的状态作为局部状态使用。此时 Model State 的变化,只会引起当前组件的重新渲染,但是不会引起其他使用了该 Model 的组件重新渲染。效果和通过 React 的 `useState` 管理状态类似,但是可以将状态的管理逻辑从组件中解耦,统一收敛到 Model 层。
168
+
169
+ :::info 注
170
+ `useLocalModel` 的使用方式和 `useModel` 完全一致。
171
+ :::
172
+
173
+ 例如,我们修改计数器应用的代码,添加一个有局部状态的计数器组件 `LocalCounter`:
174
+
175
+ ``` ts
176
+ import { useLocalModel } from '@modern-js/runtime/model';
177
+
178
+ function LocalCounter() {
179
+ const [state, actions] = useLocalModel(countModel);
180
+
181
+ return (
182
+ <div>
183
+ <div>local counter: {state.value}</div>
184
+ <button onClick={() => actions.add()}>add</button>
185
+ </div>
186
+ );
187
+ }
188
+ ```
189
+
190
+ 分别点击 `Counter` 和 `LocalCounter` 的 `add` 按钮,两者的状态互不影响:
191
+
192
+ ![local-model](https://lf3-static.bytednsdoc.com/obj/eden-cn/eueh7vhojuh/modern/local-model.gif)
193
+
194
+ 完整的示例代码可以在[这里](https://github.com/modern-js-dev/modern-js-examples/tree/main/series/tutorials/runtime-api/model/local-model)查看。
195
+
196
+
197
+
198
+ ## 在组件外使用
199
+
200
+ 在实际业务场景中,有时候我们需要在 React 组件外使用 Model,例如在工具函数中访问 State、执行 Actions 等。这个时候,我们就需要使用 Store。 Store 是一个底层概念,一般情况下用户接触不到,它负责存储和管理整个应用的状态。Reduck 的 Store 基于 [Redux 的 Store](https://redux.js.org/api/store) 实现,增加了 Reduck 特有的 API,如 `use` 。
201
+
202
+ 首先,在组件内调用 `useStore` 获取当前应用使用的 `store` 对象,并挂载到组件外的变量上:
203
+
204
+ ```ts
205
+ let store; // 组件外部 `store` 对象的引用
206
+ function setStore(s) { store = s };
207
+ function getStore() { return store };
208
+
209
+ function Counter() {
210
+ const [state] = useModel(countModel);
211
+ const store = useStore();
212
+ // 通过 useMemo 避免不必要的重复设置
213
+ useMemo(()=> {
214
+ setStore(store)
215
+ }, [store])
216
+
217
+ return (
218
+ <div>
219
+ <div>counter: {state.value}</div>
220
+ </div>
221
+ );
222
+ }
223
+ ```
224
+
225
+ 通过 `store.use` 可以获取 Model 对象,`store.use` 的用法同 `useModel` 相同。以计数器应用为例,我们在组件树外,每 1s 对计数器值
226
+ 执行自增操作:
227
+
228
+ ```ts
229
+ setInterval(() => {
230
+ const store = getStore();
231
+ const [, actions] = store.use(countModel);
232
+ actions.add();
233
+ }, 1000)
234
+ ```
235
+
236
+ 完整的示例代码可以在[这里](https://github.com/modern-js-dev/modern-js-examples/tree/main/series/tutorials/runtime-api/model/counter-model-outof-react)查看。
237
+
238
+ :::info 注
239
+ 如果是通过 [`createStore`](/docs/apis/app/runtime/model/create-store) 手动创建的 Store 对象,无需通过 `useStore` 在组件内获取,即可直接使用。
240
+ :::
241
+
242
+ :::info 补充信息
243
+ 本节涉及的 API 的详细定义,请参考[这里](/docs/apis/app/runtime/model/model_)。
244
+ :::
@@ -0,0 +1,51 @@
1
+ ---
2
+ sidebar_position: 12
3
+ title: 单独使用 Reduck
4
+ ---
5
+
6
+ 在 Modern.js 以外,单独集成 Reduck 使用时,主要需要做以下修改:
7
+
8
+ 1. 安装 Reduck 相关包
9
+
10
+ 在项目中安装 Reduck 包:`@modern-js-reduck/react`。
11
+
12
+
13
+ 2. API 导入包名
14
+
15
+ 在 Modern.js 中使用时,Reduck 导出 API 的包名为:`@modern-js/runtime/model`。单独使用 Reduck 时,导出包名为:`@modern-js-reduck/react`。
16
+
17
+
18
+ 3. 包裹 `Provider` 组件
19
+
20
+ Modern.js 自动在应用的入口组件上,包裹了用于注入 Reduck 全局 Store 的 [`Provider`](/docs/apis/app/runtime/model/Provider) 组件。单独使用 Reduck 时,需要手动完成。
21
+
22
+ 示例:
23
+ ```tsx
24
+ // 根组件
25
+ const Root = () => {
26
+ return (
27
+ <Provider>
28
+ {/* 应用入口组件 */}
29
+ <App />
30
+ </Provider>
31
+ )
32
+ }
33
+ ```
34
+
35
+
36
+ 4. 功能配置
37
+
38
+ 在 Modern.js 中使用时,可以通过 [`runtime.state`](/docs/configure/app/runtime/state) 对 Reduck 功能进行配置。单独使用时,需要通过 [`Provider`](/docs/apis/app/runtime/model/Provider) 的 `config` 或 `store` 参数配置。
39
+
40
+
41
+ 示例:
42
+ ```tsx
43
+ const Root = () => {
44
+ return (
45
+ {/* 关闭 Redux DevTools */}
46
+ <Provider config={{ devTools: false }}>
47
+ <App />
48
+ </Provider>
49
+ )
50
+ }
51
+ ```
@@ -0,0 +1,5 @@
1
+ {
2
+ "label": "First App",
3
+ "position": 2,
4
+ "collapsed": false
5
+ }
@@ -0,0 +1,99 @@
1
+ ---
2
+ title: 创建项目
3
+ ---
4
+
5
+ 从这一章节开始,我们将进入实战教程部分。在实战教程中,我们将会从环境准备开始,从简单到复杂,一步一步搭建一个真实的项目。
6
+
7
+ ## 环境准备
8
+
9
+ import Prerequisites from '@site-docs/components/prerequisites.md'
10
+
11
+ <Prerequisites />
12
+
13
+ ## 初始化项目
14
+
15
+ 我们创建新的目录,通过命令行工具初始化项目:
16
+
17
+ ```bash
18
+ mkdir myapp && cd myapp
19
+ npx @modern-js/create
20
+ ```
21
+
22
+ import InitApp from '@site-docs/components/init-app.md'
23
+
24
+ <InitApp />
25
+
26
+ ## 调试项目
27
+
28
+ import DebugApp from '@site-docs/components/debug-app.md'
29
+
30
+ <DebugApp />
31
+
32
+ ## 修改代码
33
+
34
+ 我们将原本的示例代码删除,替换成一个简单的联系人列表:
35
+
36
+ ```tsx title="src/routes/page.tsx"
37
+ const getAvatar = (users: Array<{ name: string; email: string }>) =>
38
+ users.map(user => ({
39
+ ...user,
40
+ avatar: `https://avatars.dicebear.com/v2/identicon/${user.name}.svg`,
41
+ }));
42
+
43
+ const mockData = getAvatar([
44
+ { name: 'Thomas', email: 'w.kccip@bllmfbgv.dm' },
45
+ { name: 'Chow', email: 'f.lfqljnlk@ywoefljhc.af' },
46
+ { name: 'Bradley', email: 'd.wfovsqyo@gpkcjwjgb.fr' },
47
+ { name: 'Davis', email: '"t.kqkoj@utlkwnpwk.nu' },
48
+ ]);
49
+
50
+ function App() {
51
+ return (
52
+ <ul>
53
+ {mockData.map(({ name, avatar, email }) => (
54
+ <li key={name}>
55
+ <img src={avatar} width={60} height={60} /> ---
56
+ <span>{name}</span> ---
57
+ <span>{email}</span>
58
+ </li>
59
+ ))}
60
+ </ul>
61
+ );
62
+ }
63
+
64
+ export default App;
65
+ ```
66
+
67
+ 删除多余的 css 文件,保持目录没有多余的文件:
68
+
69
+ ```bash
70
+ rm src/routes/index.css
71
+ ```
72
+
73
+ 因为框架默认支持 [HMR](https://webpack.js.org/concepts/hot-module-replacement/),可以看到 `http://localhost:8080/` 里的内容会自动更新为:
74
+
75
+ ![result](https://lf3-static.bytednsdoc.com/obj/eden-cn/zq-uylkvt/ljhwZthlaukjlkulzlp/screenshot-20221214-141909.png)
76
+
77
+ 此刻的页面还没有样式。下一章节将展开这部分的内容。
78
+
79
+ ## 开启 SSR
80
+
81
+ 接下来,我们修改项目中的 `modern.config.ts`,开启 SSR 能力:
82
+
83
+ ```ts
84
+ import AppToolsPlugin, { defineConfig } from '@modern-js/app-tools';
85
+
86
+ // https://modernjs.dev/docs/apis/app/config
87
+ export default defineConfig({
88
+ runtime: {
89
+ router: true,
90
+ state: true,
91
+ },
92
+ server: {
93
+ ssr: true,
94
+ },
95
+ plugins: [AppToolsPlugin()],
96
+ });
97
+ ```
98
+
99
+ 重新执行 `pnpm run dev`,可以发现项目已经在服务端完成了页面渲染。
@@ -0,0 +1,56 @@
1
+ ---
2
+ title: 编写 UI 组件
3
+ ---
4
+
5
+ 上一章节中,我们学习了如何初始化项目,并使用配置修改 Modern.js 的默认行为。
6
+
7
+ 这一章节中,我们继续沿用上一章节的项目代码,继续完善联系人列表。
8
+
9
+ 为了做更好的 UI 展示和交互,我们引入组件库 [Antd](https://ant.design/index-cn) 来开发,使用 `<List>` 组件来代替原始的列表。先添加依赖:
10
+
11
+ ```bash
12
+ pnpm add antd
13
+ ```
14
+
15
+ 修改 `src/routes/page.tsx`,在顶部导入组件:
16
+
17
+ ```ts
18
+ import { List } from 'antd';
19
+ ```
20
+
21
+ 修改 `<App>` 组件的实现:
22
+
23
+ ```tsx
24
+ function App() {
25
+ return (
26
+ <div>
27
+ <List
28
+ dataSource={mockData}
29
+ renderItem={({ name, email, avatar }) => (
30
+ <List.Item key={name}>
31
+ <List.Item.Meta
32
+ avatar={<img alt="avatar" src={avatar} width={60} height={60} />}
33
+ title={name}
34
+ description={email}
35
+ />
36
+ </List.Item>
37
+ )}
38
+ />
39
+ </div>
40
+ );
41
+ }
42
+ ```
43
+
44
+ 执行 `pnpm run dev`,查看运行结果:
45
+
46
+ ![result](https://lf3-static.bytednsdoc.com/obj/eden-cn/nuvjhpqnuvr/modern-website/tutorials/c02-antd-result.png)
47
+
48
+ 可以看到 Ant Design 导出的组件,已经具备了完整的样式。
49
+
50
+ :::info 注
51
+ Modern.js 会[自动按需导入 Ant Design 组件需要的 CSS](https://github.com/ant-design/babel-plugin-import)。
52
+ :::
53
+
54
+ :::note
55
+ 我们也可以使用其他组件库来实现同样的功能,例如 [Arco Design](https://arco.design/)。
56
+ :::