@modern-js/main-doc 2.0.0-beta.3 → 2.0.0-beta.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/en/docusaurus-plugin-content-docs/current/apis/app/commands/dev.md +8 -3
  3. package/en/docusaurus-plugin-content-docs/current/apis/app/commands/inspect.md +31 -10
  4. package/en/docusaurus-plugin-content-docs/current/apis/app/commands/serve.md +32 -0
  5. package/en/docusaurus-plugin-content-docs/current/apis/app/hooks/src/server.md +31 -0
  6. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/core/bootstrap.md +4 -3
  7. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/core/create-app.md +2 -3
  8. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/core/use-module-apps.md +1 -1
  9. package/en/docusaurus-plugin-content-docs/current/components/init-app.md +42 -0
  10. package/en/docusaurus-plugin-content-docs/current/configure/app/builder-plugins.md +70 -0
  11. package/en/docusaurus-plugin-content-docs/current/configure/app/dev/with-master-app.md +0 -1
  12. package/en/docusaurus-plugin-content-docs/current/configure/app/plugins.md +11 -5
  13. package/en/docusaurus-plugin-content-docs/current/configure/app/server/routes.md +2 -4
  14. package/en/docusaurus-plugin-content-docs/current/configure/app/source/disable-entry-dirs.md +38 -0
  15. package/en/docusaurus-plugin-content-docs/current/configure/app/source/entries.md +66 -2
  16. package/en/docusaurus-plugin-content-docs/current/configure/app/tools/esbuild.md +16 -39
  17. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/css/css-in-js.md +38 -0
  18. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/css/css-modules.md +86 -0
  19. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/css/less-sass.md +17 -0
  20. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/css/postcss.md +81 -0
  21. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/css/tailwindcss.md +95 -0
  22. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/data-fetch.md +66 -0
  23. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/routes.md +270 -0
  24. package/en/docusaurus-plugin-content-docs/current/guides/concept/entries.md +116 -0
  25. package/en/docusaurus-plugin-content-docs/current/guides/get-started/quick-start.md +162 -0
  26. package/en/docusaurus-plugin-content-docs/current/guides/get-started/upgrade.md +78 -0
  27. package/{zh/tutorials/first-app → en/docusaurus-plugin-content-docs/current/guides}/overview.md +4 -4
  28. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/_category_.json +4 -0
  29. package/en/docusaurus-plugin-content-docs/current/guides/topic-detail/framework-plugin/lifecycle.md +15 -0
  30. package/en/docusaurus-plugin-content-docs/current/tutorials/foundations/introduction.md +1 -1
  31. package/en/docusaurus-plugin-content-docs/current.json +11 -11
  32. package/package.json +4 -4
  33. package/zh/apis/app/commands/dev.md +9 -4
  34. package/zh/apis/app/commands/inspect.md +32 -11
  35. package/zh/apis/app/commands/new.md +1 -1
  36. package/zh/apis/app/commands/{start.md → serve.md} +3 -3
  37. package/zh/apis/app/hooks/src/index_.md +5 -4
  38. package/zh/apis/app/hooks/src/server.md +31 -0
  39. package/zh/apis/app/runtime/core/bootstrap.md +3 -4
  40. package/zh/apis/app/runtime/core/create-app.md +1 -18
  41. package/zh/apis/app/runtime/core/use-module-apps.md +64 -33
  42. package/zh/apis/app/runtime/web-server/hook.md +1 -1
  43. package/zh/apis/app/runtime/web-server/middleware.md +1 -0
  44. package/zh/components/debug-app.md +18 -0
  45. package/zh/components/default-mwa-generate.md +5 -0
  46. package/zh/components/deploy.md +1 -0
  47. package/zh/components/enable-micro-frontend.md +13 -0
  48. package/zh/components/global-proxy.md +28 -0
  49. package/zh/components/init-app.md +44 -0
  50. package/zh/components/micro-runtime-config.md +18 -0
  51. package/zh/components/prerequisites.md +19 -0
  52. package/zh/components/release-note.md +1 -0
  53. package/zh/configure/app/builder-plugins.md +72 -0
  54. package/zh/configure/app/deploy/_category_.json +4 -0
  55. package/zh/configure/app/deploy/microFrontend.md +64 -0
  56. package/zh/configure/app/dev/with-master-app.md +0 -2
  57. package/zh/configure/app/plugins.md +10 -4
  58. package/zh/configure/app/runtime/master-app.md +33 -36
  59. package/zh/configure/app/server/routes.md +2 -4
  60. package/zh/configure/app/source/disable-entry-dirs.md +37 -0
  61. package/zh/configure/app/source/entries-dir.md +0 -3
  62. package/zh/configure/app/source/entries.md +66 -3
  63. package/zh/configure/app/tools/esbuild.md +16 -39
  64. package/zh/guides/advanced-features/bff/bff-proxy.md +1 -1
  65. package/zh/guides/advanced-features/compatibility.md +14 -39
  66. package/zh/guides/advanced-features/eslint.md +21 -21
  67. package/zh/guides/advanced-features/ssg.md +20 -9
  68. package/zh/guides/advanced-features/ssr.md +95 -52
  69. package/zh/guides/advanced-features/testing.md +44 -1
  70. package/zh/guides/advanced-features/web-server.md +14 -3
  71. package/zh/guides/basic-features/css/tailwindcss.md +13 -6
  72. package/zh/guides/basic-features/data-fetch.md +398 -5
  73. package/zh/guides/basic-features/html.md +182 -0
  74. package/zh/guides/basic-features/mock.md +3 -9
  75. package/zh/guides/basic-features/proxy.md +2 -27
  76. package/zh/guides/basic-features/routes.md +35 -3
  77. package/zh/guides/concept/entries.md +108 -19
  78. package/zh/guides/get-started/quick-start.md +14 -83
  79. package/zh/guides/get-started/upgrade.md +11 -9
  80. package/zh/guides/{concept → topic-detail/framework-plugin}/lifecycle.md +0 -0
  81. package/zh/guides/topic-detail/micro-frontend/c01-introduction.md +29 -0
  82. package/zh/guides/topic-detail/micro-frontend/c02-development.md +191 -0
  83. package/zh/guides/topic-detail/micro-frontend/c03-main-app.md +246 -0
  84. package/zh/guides/topic-detail/micro-frontend/c04-communicate.md +54 -0
  85. package/zh/guides/topic-detail/micro-frontend/{mixed-stack.md → c05-mixed-stack.md} +3 -3
  86. package/zh/guides/topic-detail/model/quick-start.md +1 -1
  87. package/zh/guides/topic-detail/model/test-model.md +2 -2
  88. package/zh/guides/topic-detail/monorepo/create-sub-project.md +2 -2
  89. package/zh/guides/topic-detail/monorepo/intro.md +1 -1
  90. package/zh/guides/troubleshooting/dependencies.md +0 -69
  91. package/zh/tutorials/first-app/_category_.json +1 -1
  92. package/zh/tutorials/first-app/c01-start.md +99 -0
  93. package/zh/tutorials/first-app/{c05-component/5.1-use-ui-library.md → c02-component.md} +13 -15
  94. package/zh/tutorials/first-app/c03-css.md +324 -0
  95. package/zh/tutorials/first-app/{c08-client-side-routing/8.1-code-based-routing.md → c04-routes.md} +52 -39
  96. package/zh/tutorials/first-app/c05-loader.md +82 -0
  97. package/zh/tutorials/first-app/c06-model.md +256 -0
  98. package/zh/tutorials/first-app/c07-container.md +283 -0
  99. package/zh/tutorials/first-app/c08-entries.md +137 -0
  100. package/zh/tutorials/foundations/introduction.md +1 -1
  101. package/en/docusaurus-plugin-content-docs/current/apis/app/commands/start.md +0 -32
  102. package/en/docusaurus-plugin-content-docs/current/configure/app/output/enable-modern-mode.md +0 -34
  103. package/zh/apis/generator/overview.md +0 -32
  104. package/zh/configure/app/output/enable-modern-mode.md +0 -34
  105. package/zh/guides/advanced-features/custom-app.md +0 -72
  106. package/zh/guides/topic-detail/micro-frontend/communicate.md +0 -39
  107. package/zh/guides/topic-detail/micro-frontend/debugging.md +0 -168
  108. package/zh/guides/topic-detail/micro-frontend/introduction.md +0 -13
  109. package/zh/guides/topic-detail/micro-frontend/route-mode.md +0 -110
  110. package/zh/guides/topic-detail/monorepo/deploy.md +0 -43
  111. package/zh/tutorials/first-app/c01-getting-started/1.1-prerequisites.md +0 -25
  112. package/zh/tutorials/first-app/c01-getting-started/1.2-minimal-mwa.md +0 -118
  113. package/zh/tutorials/first-app/c01-getting-started/1.3-dev-command.md +0 -29
  114. package/zh/tutorials/first-app/c01-getting-started/1.4-enable-ssr.md +0 -47
  115. package/zh/tutorials/first-app/c01-getting-started/1.5-start-command.md +0 -18
  116. package/zh/tutorials/first-app/c01-getting-started/1.6-create-repo.md +0 -31
  117. package/zh/tutorials/first-app/c01-getting-started/_category_.json +0 -3
  118. package/zh/tutorials/first-app/c02-generator-and-studio/2.1-generator.md +0 -79
  119. package/zh/tutorials/first-app/c02-generator-and-studio/2.2-boilerplates.md +0 -34
  120. package/zh/tutorials/first-app/c02-generator-and-studio/2.3-configuration.md +0 -19
  121. package/zh/tutorials/first-app/c02-generator-and-studio/_category_.json +0 -3
  122. package/zh/tutorials/first-app/c03-ide/3.1-setting-up.md +0 -55
  123. package/zh/tutorials/first-app/c03-ide/3.2-hints-in-ide.md +0 -60
  124. package/zh/tutorials/first-app/c03-ide/3.3-autofix-in-ide.md +0 -11
  125. package/zh/tutorials/first-app/c03-ide/3.4-autofix-in-cli.md +0 -63
  126. package/zh/tutorials/first-app/c03-ide/_category_.json +0 -3
  127. package/zh/tutorials/first-app/c04-es6-plus-and-ts/4.1-use-es6-plus.md +0 -54
  128. package/zh/tutorials/first-app/c04-es6-plus-and-ts/4.2-use-typescript.md +0 -135
  129. package/zh/tutorials/first-app/c04-es6-plus-and-ts/4.3-compatibility.md +0 -67
  130. package/zh/tutorials/first-app/c04-es6-plus-and-ts/_category_.json +0 -3
  131. package/zh/tutorials/first-app/c05-component/5.2-use-standalone-component.md +0 -72
  132. package/zh/tutorials/first-app/c05-component/_category_.json +0 -3
  133. package/zh/tutorials/first-app/c06-css-and-component/6.1-css-in-js.md +0 -110
  134. package/zh/tutorials/first-app/c06-css-and-component/6.2-utility-class.md +0 -143
  135. package/zh/tutorials/first-app/c06-css-and-component/6.3-postcss.md +0 -84
  136. package/zh/tutorials/first-app/c06-css-and-component/6.4-design-system.md +0 -83
  137. package/zh/tutorials/first-app/c06-css-and-component/6.5-storybook.md +0 -77
  138. package/zh/tutorials/first-app/c06-css-and-component/6.6-testing.md +0 -104
  139. package/zh/tutorials/first-app/c06-css-and-component/_category_.json +0 -3
  140. package/zh/tutorials/first-app/c07-app-entry/7.1-intro.md +0 -69
  141. package/zh/tutorials/first-app/c07-app-entry/7.2-add-entry-in-cli.md +0 -100
  142. package/zh/tutorials/first-app/c07-app-entry/7.3-manage-entries-by-hand.md +0 -69
  143. package/zh/tutorials/first-app/c07-app-entry/_category_.json +0 -3
  144. package/zh/tutorials/first-app/c08-client-side-routing/_category_.json +0 -3
  145. package/zh/tutorials/first-app/c09-bff/9.1-serverless.md +0 -30
  146. package/zh/tutorials/first-app/c09-bff/9.2-enable-bff.md +0 -95
  147. package/zh/tutorials/first-app/c09-bff/9.3-fetch-bff.md +0 -131
  148. package/zh/tutorials/first-app/c09-bff/_category_.json +0 -3
  149. package/zh/tutorials/first-app/c10-model/10.1-application-architecture.md +0 -21
  150. package/zh/tutorials/first-app/c10-model/10.2-add-model.md +0 -185
  151. package/zh/tutorials/first-app/c10-model/10.3-use-model.md +0 -55
  152. package/zh/tutorials/first-app/c10-model/10.4-testing.md +0 -69
  153. package/zh/tutorials/first-app/c10-model/_category_.json +0 -3
  154. package/zh/tutorials/first-app/c11-container/11.1-use-model-with-app-state.md +0 -240
  155. package/zh/tutorials/first-app/c11-container/11.2-add-container.md +0 -109
  156. package/zh/tutorials/first-app/c11-container/11.3-use-loader.md +0 -63
  157. package/zh/tutorials/first-app/c11-container/11.4-testing.md +0 -56
  158. package/zh/tutorials/first-app/c11-container/_category_.json +0 -3
@@ -0,0 +1,324 @@
1
+ ---
2
+ title: 添加样式
3
+ ---
4
+
5
+ import Tabs from '@theme/Tabs';
6
+ import TabItem from '@theme/TabItem';
7
+
8
+ 上一章节中,我们学习了如何使用使用三方库中的组件。
9
+
10
+ 这一章节中,我们将学习如何实现 UI 组件。
11
+
12
+ ## 使用 CSS 写 JS 组件
13
+
14
+ 首先我们希望自己控制联系人头像的展示,实现这种设计稿:
15
+
16
+ ![design](https://lf3-static.bytednsdoc.com/obj/eden-cn/nuvjhpqnuvr/modern-website/tutorials/c03-css-expect.jpg)
17
+
18
+ 假设没有现成的组件可以实现,那就需要自己写些 CSS 了,这里我们使用 [styled-components](https://styled-components.com/),来实现类似的需求。Modern.js 开箱即用的支持 styled-components,既不需要安装依赖,也不需要做任何配置。
19
+
20
+ styled-components 通过模块化的方式,避免了传统 CSS 写法上的诸多问题。例如直接在元素的 style 属性上写样式,UI 视觉上的细节也会跟 UI 结构上的细节和业务逻辑混在一起。或是 classname 需要避免全局空间重名,需要用到命名规范的问题。
21
+
22
+ 在 `src/routes/page.tsx` 里修改顶部的代码:
23
+
24
+ ```js
25
+ import styled from '@modern-js/runtime/styled';
26
+ ```
27
+
28
+ 添加以下代码:
29
+
30
+ ```js
31
+ const Avatar = styled.img`
32
+ width: 50px;
33
+ height: 50px;
34
+ border: 4px solid #0ef;
35
+ border-radius: 50%;
36
+ `;
37
+ ```
38
+
39
+ 修改 `List.Item.Meta` 的代码:
40
+
41
+ ```tsx
42
+ <List.Item.Meta
43
+ avatar={<Avatar src={avatar} />}
44
+ title={name}
45
+ description={email}
46
+ />
47
+ ```
48
+
49
+ 执行 `pnpm run dev`,可以看到预期的运行结果:
50
+
51
+ ![result](https://lf3-static.bytednsdoc.com/obj/eden-cn/nuvjhpqnuvr/modern-website/tutorials/c03-css-result1.png)
52
+
53
+ 接下来我们做一点重构,为了增强可读性,让代码更容易维护,可以把 Avatar 组件拆分出去。我们在终端执行以下命令,创建新的文件:
54
+
55
+ <Tabs>
56
+ <TabItem value="macOS" label="macOS" default>
57
+
58
+ ```bash
59
+ mkdir -p src/components/Avatar
60
+ touch src/components/Avatar/index.tsx
61
+ ```
62
+
63
+ </TabItem>
64
+ <TabItem value="Windows" label="Windows">
65
+
66
+ ```powershell
67
+ mkdir -p src/components/Avatar
68
+ ni src/components/Avatar/index.tsx
69
+ ```
70
+
71
+ </TabItem>
72
+ </Tabs>
73
+
74
+ 把 `src/routes/page.tsx` 里的 `<Avatar>` 实现删掉,修改为:
75
+
76
+ ```ts
77
+ import Avatar from '../components/Avatar';
78
+ ```
79
+
80
+ `src/components/Avatar/index.tsx` 的内容,修改为:
81
+
82
+ ```ts
83
+ import styled from '@modern-js/runtime/styled';
84
+
85
+ const Avatar = styled.img`
86
+ width: 50px;
87
+ height: 50px;
88
+ border: 4px solid #0ef;
89
+ border-radius: 50%;
90
+ `;
91
+
92
+ export default Avatar;
93
+ ```
94
+
95
+ 执行 `pnpm run dev`,运行结果应该是一样的。
96
+
97
+ :::info 注
98
+ 采用目录形式 `Avatar/index.tsx` 而不是单文件形式 `Avatar.tsx` 的原因是,之后可以方便的在目录内部增加子文件,包括专用的资源(图片等)、专用子组件、CSS 文件等。
99
+ :::
100
+
101
+
102
+ ## 使用 Utility
103
+
104
+ 我们已经使用 style-components 实现 `<Avatar>` 组件,但当前的 UI 仍然不能让人满意,缺乏专业感,例如列表项内部的布局有点粗糙,很多地方没对齐。
105
+
106
+ 现在,我们自己来实现一个更好的 `Item` 组件,实现这样的设计稿:
107
+
108
+ ![design](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/06/design2.png)
109
+
110
+ 这次要实现的 UI 更复杂,有内部结构,但另一方面,并没有 `<Avatar>` 组件的**很粗的亮蓝色边框**这样很特殊的 UI,都是很常规的水平垂直布局、居中、字体样式等。这种情况下,其实根本没必要写 CSS,有更高效的、跟 styled-components 互补的实现方式:**Utility Class**。
111
+
112
+ Modern.js 集成了主流、轻量、通用的 Utility Class 工具库 [Tailwind CSS](https://tailwindcss.com/)。
113
+
114
+ 执行 `pnpm run new`,进行如下选择,开启 Tailwind CSS:
115
+
116
+ ```bash
117
+ ? 请选择你想要的操作 启用可选功能
118
+ ? 启用可选功能 启用 Tailwind CSS 支持
119
+ ```
120
+
121
+ 在 `modern.config.ts` 中注册 Tailwind 插件:
122
+
123
+ ```ts title="modern.config.ts"
124
+ import AppToolsPlugin, { defineConfig } from '@modern-js/app-tools';
125
+ import TailwindCSSPlugin from '@modern-js/plugin-tailwindcss';
126
+
127
+ // https://modernjs.dev/docs/apis/app/config
128
+ export default defineConfig({
129
+ runtime: {
130
+ router: true,
131
+ state: true,
132
+ },
133
+ server: {
134
+ ssr: true,
135
+ },
136
+ plugins: [AppToolsPlugin(), TailwindCSSPlugin()],
137
+ });
138
+ ```
139
+
140
+ 在 `src/routes/page.tsx` 顶部引入 Tailwind CSS 的 css 文件,就可以开始快速实现专业的 UI:
141
+
142
+ ```js
143
+ import 'tailwindcss/base.css';
144
+ import 'tailwindcss/components.css';
145
+ import 'tailwindcss/utilities.css';
146
+ ```
147
+
148
+ 先创建 Item 组件:
149
+
150
+ <Tabs>
151
+ <TabItem value="macOS" label="macOS" default>
152
+
153
+ ```bash
154
+ mkdir -p src/components/Item
155
+ touch src/components/Item/index.tsx
156
+ ```
157
+
158
+ </TabItem>
159
+ <TabItem value="Windows" label="Windows">
160
+
161
+ ```powershell
162
+ mkdir -p src/components/Item
163
+ ni src/components/Item/index.tsx
164
+ ```
165
+
166
+ </TabItem>
167
+ </Tabs>
168
+
169
+ 修改 `src/routes/page.tsx`,把 `List` 的 `render` 实现交给 `Item` 组件:
170
+
171
+ ```js
172
+ import { List } from 'antd';
173
+ import 'tailwindcss/base.css';
174
+ import 'tailwindcss/components.css';
175
+ import 'tailwindcss/utilities.css';
176
+ import Item from '../components/Item';
177
+
178
+ const getAvatar = (users: Array<{ name: string; email: string }>) =>
179
+ users.map(user => ({
180
+ ...user,
181
+ avatar: `https://avatars.dicebear.com/v2/identicon/${user.name}.svg`,
182
+ }));
183
+
184
+ const mockData = getAvatar([
185
+ { name: 'Thomas', email: 'w.kccip@bllmfbgv.dm' },
186
+ { name: 'Chow', email: 'f.lfqljnlk@ywoefljhc.af' },
187
+ { name: 'Bradley', email: 'd.wfovsqyo@gpkcjwjgb.fr' },
188
+ { name: 'Davis', email: '"t.kqkoj@utlkwnpwk.nu' },
189
+ ]);
190
+
191
+ function Index() {
192
+ return (
193
+ <div className="container lg mx-auto">
194
+ <List
195
+ dataSource={mockData}
196
+ renderItem={info => <Item key={info.name} info={info} />}
197
+ />
198
+ </div>
199
+ );
200
+ }
201
+
202
+ export default Index;
203
+ ```
204
+
205
+ 在父容器的上使用了 [Utility Class](https://tailwindcss.com/docs/container) ,快速实现了最基本的最大宽度、居中等样式。
206
+
207
+ 接下来实现 `src/components/Item/index.tsx`:
208
+
209
+ ```tsx
210
+ import Avatar from '../Avatar';
211
+
212
+ type InfoProps = {
213
+ avatar: string;
214
+ name: string;
215
+ email: string;
216
+ archived?: boolean;
217
+ };
218
+
219
+ const Item = ({ info }: { info: InfoProps }) => {
220
+ const { avatar, name, email, archived } = info;
221
+ return (
222
+ <div className="flex p-4 items-center border-gray-200 border-b">
223
+ <Avatar src={avatar} />
224
+ <div className="ml-4 flex-1 flex justify-between">
225
+ <div className="flex-1">
226
+ <p>{name}</p>
227
+ <p>{email}</p>
228
+ </div>
229
+ <button
230
+ type="button"
231
+ disabled={archived}
232
+ className={`bg-blue-500 text-white font-bold
233
+ py-2 px-4 rounded-full hover:bg-blue-700`}
234
+ >
235
+ Archive
236
+ </button>
237
+ </div>
238
+ </div>
239
+ );
240
+ };
241
+
242
+ export default Item;
243
+ ```
244
+
245
+ 执行 `pnpm run dev`,可以看到预期的运行结果:
246
+
247
+ ![result](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/06/result2.png)
248
+
249
+ 我们只使用了少量 Utility Class,比如 [Flex](https://tailwindcss.com/docs/display/)、[Padding](https://tailwindcss.com/docs/padding/)、[Margin](https://tailwindcss.com/docs/margin/)、[Text](https://tailwindcss.com/docs/text-color/)、[Font](https://tailwindcss.com/docs/font-weight/)、[Border](https://tailwindcss.com/docs/border-width),不写一行 CSS 就实现了符合设计稿的专业 UI。
250
+
251
+
252
+ ## 自定义 Utility Class
253
+
254
+ 我们也可以自己实现新的 Utility Class,方便在代码间复用。
255
+
256
+ Utility Class 本身也是一种**面向组件**的技术(将不同 class 用在一个组件上,等价于给这个组件设置了一些来自基类的属性),但 Utility Class 的 classname 是全局的(因为要用在任意组件/元素上),很适合用独立 CSS 文件来实现。
257
+
258
+ 创建一个新的 CSS 文件:
259
+
260
+ <Tabs>
261
+ <TabItem value="macOS" label="macOS" default>
262
+
263
+ ```bash
264
+ mkdir -p src/styles
265
+ touch src/styles/utils.css
266
+ ```
267
+
268
+ </TabItem>
269
+ <TabItem value="Windows" label="Windows">
270
+
271
+ ```powershell
272
+ mkdir -p src/styles
273
+ ni src/styles/utils.css
274
+ ```
275
+
276
+ </TabItem>
277
+ </Tabs>
278
+
279
+ 在 `src/routes/page.tsx` 里导入 `utils.css`:
280
+
281
+ ```js
282
+ import '../styles/utils.css';
283
+ ```
284
+
285
+ 在 `src/routes/styles/utils.css` 里实现一个名为 `custom-text-gray` 的 Utility Class。
286
+
287
+ ```css
288
+ :root {
289
+ --custom-text-color:rgb(113, 128, 150);
290
+ }
291
+
292
+ .custom-text-gray {
293
+ color: var(--custom-text-color);
294
+ }
295
+ ```
296
+
297
+ :::info 注
298
+ Modern.js 集成了 [PostCSS](/docs/guides/basic-features/css/postcss),支持现代 CSS 语法特性,比如 [custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/--*)。
299
+ :::
300
+
301
+ 在 `src/routes/components/Item/index.tsx` 里使用,把:
302
+
303
+ ```js
304
+ <div className="ml-4 flex-1 flex justify-between">
305
+ ```
306
+
307
+ 改成:
308
+
309
+ ```js
310
+ <div className="ml-4 custom-text-gray flex-1 flex justify-between">
311
+ ```
312
+
313
+ 执行 `pnpm run dev`,可以看到字体颜色改变了:
314
+
315
+ ![design2](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/06/result3.png)
316
+
317
+ :::info 注
318
+ 此处只是为了演示 Utility Class 用法。真实项目中,在有 Tailwind CSS 的情况下,这种 Utility Class 没什么价值,应该通过配置 Design System 的 [**theme**](https://tailwindcss.com/docs/customizing-colors) 来增加字体颜色。
319
+
320
+ `utils.css` 也可以写成 `utils.scss` 或 `utils.less`,Modern.js 对 SCSS 和 Less 同样提供开箱即用的支持。
321
+
322
+ 不过在 PostCSS 的支持下,现代 CSS 应该足以满足这些开发需求,性能相较于预处理器也更好,建议优先用 .css 文件。
323
+ :::
324
+
@@ -1,32 +1,43 @@
1
1
  ---
2
- title: 使用约定式路由​​​​
2
+ title: 添加客户端路由
3
3
  ---
4
4
 
5
- 上一章节中,我们学习了如何创建应用入口。
5
+ import Tabs from '@theme/Tabs';
6
+ import TabItem from '@theme/TabItem';
6
7
 
7
- 这一章节中,我们将会学习如何为入口增加【 客户端路由 】。
8
+ 上一章节中,我们学习了如何为创建 UI 组件,并添加样式。
8
9
 
9
- 我们分别用两种不同的方式,为 `contacts` 和 `landing-page` 增加客户端路由逻辑。
10
+ 这一章节中,我们将会学习如何添加**客户端路由**。
10
11
 
11
- `contacts` `landing-page` 这两个入口,都是通过 CLI 自动创建出来的,在创建过程中我们没有修改入口的默认配置,因此每个入口的客户端路由都是默认开启的。
12
+ 之前我们已经为联系人列表增加了 Archive 按钮,接下来我们添加一个客户端路由 `/archives`,访问这个路由时,只显示已存档的联系人,而原有的 `/` 继续显示所有联系人。
13
+
14
+ 新建 `src/routes/archives/page.tsx` 文件:
15
+
16
+ <Tabs>
17
+ <TabItem value="macOS" label="macOS" default>
12
18
 
13
- ```js title="modern.config.ts"
14
- export default defineConfig({
15
- runtime: {
16
- router: true,
17
- state: true,
18
- },
19
- });
19
+ ```bash
20
+ mkdir -p src/routes/archives
21
+ touch src/routes/archives/page.tsx
20
22
  ```
21
23
 
22
- 之前我们已经为联系人列表增加了 Archive 按钮,接下来我们添加一个客户端路由 `/archives`,访问这个路由时,只显示已存档的联系人,而原有的 `/` 继续显示所有联系人。
24
+ </TabItem>
25
+ <TabItem value="Windows" label="Windows">
23
26
 
24
- 新建 `src/contacts/routes/archives/page.tsx`, 添加如下代码:
27
+ ```powershell
28
+ mkdir -p src/routes/archives
29
+ ni src/routes/archives/page.tsx
30
+ ```
25
31
 
26
- ```ts
32
+ </TabItem>
33
+ </Tabs>
34
+
35
+ 添加如下代码:
36
+
37
+ ```tsx title="src/archives/page.tsx"
27
38
  import { List } from 'antd';
28
39
  import { Helmet } from '@modern-js/runtime/head';
29
- import Item from '../components/Item';
40
+ import Item from '../../components/Item';
30
41
 
31
42
  const getAvatar = (users: Array<{ name: string; email: string }>) =>
32
43
  users.map(user => ({
@@ -56,12 +67,12 @@ function Index() {
56
67
  export default Index;
57
68
  ```
58
69
 
59
- 这里使用了 [React Helmet](https://github.com/nfl/react-helmet) 的 `Helmet` 组件,在 `src/contacts/routes/page.tsx` 中也添加 Helmet 组件:
70
+ 这里使用了 [React Helmet](https://github.com/nfl/react-helmet) 的 `Helmet` 组件,在 `src/routes/page.tsx` 中也添加 Helmet 组件:
60
71
 
61
72
  ```tsx
62
73
  import { Helmet } from '@modern-js/runtime/head';
63
74
 
64
- function App() {
75
+ function Index() {
65
76
  return (
66
77
  <div className="container lg mx-auto">
67
78
  <Helmet>
@@ -74,30 +85,39 @@ function App() {
74
85
  ```
75
86
 
76
87
  :::info 注
77
- Modern.js 默认集成了 react-helmet,无需安装依赖,可以直接使用,也可以结合 SSR 使用,满足 SEO 需求。
88
+ Modern.js 默认集成了 react-helmet,也可以结合 SSR 使用,满足 SEO 需求。
78
89
  :::
79
90
 
80
- 执行 `pnpm run dev`,访问 `http://localhost:8080/contacts`,可以看到完整的联系人,页面的标题是 All:
91
+ 因为现在有多个页面,都需要用到前面的 Utility Class,因此我们需要把样式文件移动到 `src/routes/layout.tsx`:
81
92
 
82
- ![display](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/08/display.png)
93
+ ```tsx
94
+ import 'tailwindcss/base.css';
95
+ import 'tailwindcss/components.css';
96
+ import 'tailwindcss/utilities.css';
97
+ import '../styles/utils.css';
98
+ ```
99
+
100
+ 执行 `pnpm run dev`,访问 `http://localhost:8080`,可以看到完整的联系人,页面的标题是 All:
83
101
 
84
- 访问 `http://localhost:8080/contacts/archives`,只会看到已存档的联系人,页面的标题是 Archives:
102
+ ![display1](https://lf3-static.bytednsdoc.com/obj/eden-cn/nuvjhpqnuvr/modern-website/tutorials/c04-archives.png)
85
103
 
86
- ![display1](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/08/display1.png)
104
+ 访问 `http://localhost:8080/archives`,只会看到已存档的联系人,页面的标题是 Archives:
105
+
106
+ ![display](https://lf3-static.bytednsdoc.com/obj/eden-cn/nuvjhpqnuvr/modern-website/tutorials/c04-all.png)
87
107
 
88
108
  查看页面 HTML 源码,可以看到两个页面的内容是一样,是在客户端针对不同 URL 渲染不同内容。
89
109
 
90
110
  **接下来我们增加一个简单的导航栏,让用户能在两个列表之间切换**。
91
111
 
92
- 打开 `src/contacts/layout.tsx`,在顶部导入 Radio 组件:
112
+ 打开 `src/routes/layout.tsx`,在顶部导入 Radio 组件:
93
113
 
94
114
  ```tsx
95
- import { List, Radio } from 'antd';
115
+ import { Radio } from 'antd';
96
116
  ```
97
117
 
98
118
  然后将 UI 最顶部进行修改,增加一组单选框
99
119
 
100
- ```tsx {5-8}
120
+ ```tsx {4-9}
101
121
  export default function Layout() {
102
122
  return (
103
123
  <div>
@@ -111,7 +131,6 @@ export default function Layout() {
111
131
  </div>
112
132
  );
113
133
  }
114
-
115
134
  ```
116
135
 
117
136
  然后我们来实现 `currentList` 和 `handleSetList`。
@@ -121,16 +140,16 @@ export default function Layout() {
121
140
  ```js
122
141
  import { useState } from 'react';
123
142
  import { Radio, RadioChangeEvent } from 'antd';
124
- import { Outlet, useNavigate, useParams } from '@modern-js/runtime/router';
143
+ import { Outlet, useLocation, useNavigate } from "@modern-js/runtime/router";
125
144
  ```
126
145
 
127
146
  最后在 Layout 组件里增加局部状态和相关逻辑:
128
147
 
129
- ```js {2-8}
148
+ ```tsx {2-9}
130
149
  export default function Layout() {
131
150
  const navigate = useNavigate();
132
- const params = useParams();
133
- const [currentList, setList] = useState(params.pathname || '/');
151
+ const location = useLocation();
152
+ const [currentList, setList] = useState(location.pathname || '/');
134
153
  const handleSetList = (e: RadioChangeEvent) => {
135
154
  const { value } = e.target;
136
155
  setList(value);
@@ -143,14 +162,8 @@ export default function Layout() {
143
162
 
144
163
  到这里就已经完成了页面导航栏实现,执行 `pnpm run dev` 查看效果:
145
164
 
146
- ![display2](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/08/display2.png)
165
+ ![display2](https://lf3-static.bytednsdoc.com/obj/eden-cn/nuvjhpqnuvr/modern-website/tutorials/c04-switch.png)
147
166
 
148
167
  点击导航栏中 Archives,可以看到单选框的选中状态和 URL 都会变化,页面没有刷新,只发生了 CSR。
149
168
 
150
- 如果我们将 contacts 入口的 SSR 选项开启后([配置教程](/docs/configure/app/server/ssr)),重新访问两个页面,可以看到 HTML 内容是不同的,这是因为在 SSR 阶段页面就执行了客户端路由的逻辑,HTML 里已经包含了最终的渲染结果。
151
-
152
- 访问 `http://localhost:8080/contacts/archives`,点击顶部单选框,可以看到在有 SSR 的情况下,CSR 不受影响,跟开启 SSR 之前的效果一致,实现了 UX 的最大化(首屏 SSR,后续交互 CSR)。
153
-
154
- ---
155
-
156
- > 本小节的代码可以在[这里查看](https://github.com/modern-js-dev/modern-js-examples/tree/main/tutorials/c08/hello-modern)。
169
+ 通过 URL 访问两个页面,可以看到 HTML 内容是不同的,这是因为在 SSR 阶段页面就执行了客户端路由的逻辑,HTML 里已经包含了最终的渲染结果。
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: 添加 Loader
3
+ ---
4
+
5
+ 上一章节中,我们学习了如何添加客户端路由。
6
+
7
+ 这一章节中,我们将会学习如何为**路由组件添加 Loader**。
8
+
9
+ 到目前为止,我们都是通过硬编码的方式,为组件提供数据。如果要从远端获取数据,通常情况下会使用 `useEffect` 来做。但在启用 SSR 的情况下,`useEffect` 是不会在服务端执行的,所以这种 SSR 只能渲染很有限的 UI。
10
+
11
+ Modern.js 为提供了 Data Loader 的能力,支持同构的在组件中获取数据,让 SSR 的价值最大化。
12
+
13
+ 下面我们演示如何为路由组件添加 Data Loader,并模拟远端数据获取。我们使用 faker 来 mock 需要的数据,首先安装依赖:
14
+
15
+ ```bash
16
+ pnpm add faker@5
17
+ pnpm add @types/faker@5 -D
18
+ ```
19
+
20
+ 修改 `src/routes/page.tsx`:
21
+
22
+ ```tsx
23
+ import { name, internet } from 'faker';
24
+
25
+ type LoaderData = {
26
+ code: number;
27
+ data: {
28
+ name: string;
29
+ avatar: string;
30
+ email: string;
31
+ }[];
32
+ };
33
+
34
+ export const loader = async (): Promise<LoaderData> => {
35
+ const data = new Array(20).fill(0).map(() => {
36
+ const firstName = name.firstName();
37
+ return {
38
+ name: firstName,
39
+ avatar: `https://avatars.dicebear.com/api/identicon/${firstName}.svg`,
40
+ email: internet.email(),
41
+ };
42
+ });
43
+
44
+ return {
45
+ code: 200,
46
+ data,
47
+ };
48
+ };
49
+ ```
50
+
51
+ :::note
52
+ Data Loader 并非只为 SSR 工作。在 CSR 项目中,Data Loader 也可以避免数据获取依赖 UI 渲染,解决请求瀑布流的问题。未来,Modern.js 也会为这一特性添加更多能力,例如预获取、数据缓存等。
53
+ :::
54
+
55
+ Modern.js 也提供了一个叫 `useLoaderData` 的 hooks API,我们修改 `src/routes/page.tsx` 导出的组件:
56
+
57
+ ```tsx {1,4,13}
58
+ import { useLoaderData } from '@modern-js/runtime/router';
59
+
60
+ function Index() {
61
+ const { data } = useLoaderData() as LoaderData;
62
+
63
+ return (
64
+ <div className="container lg mx-auto">
65
+ <Helmet>
66
+ <title>All</title>
67
+ </Helmet>
68
+ <List
69
+ dataSource={data}
70
+ renderItem={(info) => <Item key={info.name} info={info} />}
71
+ />
72
+ </div>
73
+ );
74
+ }
75
+
76
+ export default Index;
77
+ ```
78
+
79
+ <!-- Todo 重新截图,SSR 内容 -->
80
+ 重新执行 `pnpm run dev`,查看 `view-source:http://localhost:8080/`,或在 devtools 的 Network 面板里查看 HTML 请求的「 Preview 」,可以看到 SSR 渲染出来的 HTML 已经包含完整的 UI:
81
+
82
+ ![display6](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/11/display6.png)