@modern-js/main-doc 2.35.1 → 2.36.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. package/docs/en/apis/app/hooks/src/routes.mdx +1 -1
  2. package/docs/en/components/debug-app.mdx +1 -1
  3. package/docs/en/components/turtorials-example-list.mdx +2 -0
  4. package/docs/en/configure/app/source/entries.mdx +7 -6
  5. package/docs/en/guides/advanced-features/bff/sdk.mdx +119 -0
  6. package/docs/en/guides/advanced-features/rspack-start.mdx +1 -1
  7. package/docs/en/guides/advanced-features/ssr.mdx +17 -17
  8. package/docs/en/guides/basic-features/data/_category_.json +4 -0
  9. package/docs/en/guides/basic-features/{data-fetch.mdx → data/data-fetch.mdx} +35 -27
  10. package/docs/en/guides/basic-features/data/data-write.mdx +241 -0
  11. package/docs/en/guides/basic-features/routes.mdx +7 -7
  12. package/docs/en/guides/concept/entries.mdx +31 -30
  13. package/docs/en/guides/get-started/quick-start.mdx +1 -1
  14. package/docs/en/guides/topic-detail/framework-plugin/extend.mdx +0 -1
  15. package/docs/en/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
  16. package/docs/en/guides/topic-detail/framework-plugin/hook.mdx +1 -1
  17. package/docs/en/guides/topic-detail/framework-plugin/implement.mdx +1 -2
  18. package/docs/en/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
  19. package/docs/en/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
  20. package/docs/en/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
  21. package/docs/en/guides/topic-detail/framework-plugin/relationship.mdx +2 -2
  22. package/docs/en/guides/topic-detail/generator/new/config.md +0 -5
  23. package/docs/en/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
  24. package/docs/en/tutorials/first-app/c05-loader.mdx +2 -2
  25. package/docs/en/tutorials/first-app/c06-model.mdx +4 -4
  26. package/docs/en/tutorials/first-app/c07-container.mdx +3 -3
  27. package/docs/en/tutorials/foundations/introduction.mdx +3 -2
  28. package/docs/zh/apis/app/hooks/src/routes.mdx +1 -1
  29. package/docs/zh/components/debug-app.mdx +1 -1
  30. package/docs/zh/components/micro-runtime-config.mdx +2 -2
  31. package/docs/zh/components/turtorials-example-list.mdx +2 -0
  32. package/docs/zh/configure/app/source/entries.mdx +7 -6
  33. package/docs/zh/guides/advanced-features/bff/sdk.mdx +119 -0
  34. package/docs/zh/guides/advanced-features/rspack-start.mdx +1 -1
  35. package/docs/zh/guides/advanced-features/ssr.mdx +16 -16
  36. package/docs/zh/guides/basic-features/data/_category_.json +4 -0
  37. package/docs/zh/guides/basic-features/{data-fetch.mdx → data/data-fetch.md} +31 -27
  38. package/docs/zh/guides/basic-features/data/data-write.mdx +236 -0
  39. package/docs/zh/guides/basic-features/routes.mdx +7 -7
  40. package/docs/zh/guides/concept/entries.mdx +34 -32
  41. package/docs/zh/guides/get-started/quick-start.mdx +1 -1
  42. package/docs/zh/guides/topic-detail/framework-plugin/extend.mdx +0 -1
  43. package/docs/zh/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
  44. package/docs/zh/guides/topic-detail/framework-plugin/hook.mdx +1 -1
  45. package/docs/zh/guides/topic-detail/framework-plugin/implement.mdx +0 -1
  46. package/docs/zh/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
  47. package/docs/zh/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
  48. package/docs/zh/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
  49. package/docs/zh/guides/topic-detail/framework-plugin/relationship.mdx +1 -1
  50. package/docs/zh/guides/topic-detail/generator/new/config.md +0 -5
  51. package/docs/zh/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
  52. package/docs/zh/guides/topic-detail/monorepo/create-sub-project.mdx +0 -14
  53. package/docs/zh/guides/topic-detail/monorepo/sub-project-interface.mdx +7 -43
  54. package/docs/zh/tutorials/first-app/c05-loader.mdx +2 -2
  55. package/docs/zh/tutorials/first-app/c06-model.mdx +3 -3
  56. package/docs/zh/tutorials/first-app/c07-container.mdx +3 -3
  57. package/docs/zh/tutorials/foundations/introduction.mdx +3 -2
  58. package/package.json +7 -7
@@ -0,0 +1,236 @@
1
+ ---
2
+ title: 数据写入
3
+ sidebar_position: 4
4
+ ---
5
+
6
+ # 数据写入
7
+
8
+ 在 Data Loader 章节中,介绍了 Modern.js 获取数据的方式,你可能会遇到两个问题:
9
+ 1. 如何更新 Data Loader 中的数据?
10
+ 2. 如何将新的数据传递到服务器?
11
+
12
+ EdenX 对此的解决方案是 DataAction。
13
+
14
+ ## 基本示例
15
+
16
+ Data Action 和 Data Loader 一样,也是基于约定式路由的,通过 Modern.js 的[约定式(嵌套)路由](/guides/basic-features/routes#约定式路由),每个路由组件(`layout.ts`,`page.ts` 或 `$.tsx`)可以有一个同名的 `data` 文件,`data` 文件中可以导出一个命名为 `action` 的函数。
17
+ ```bash
18
+ .
19
+ └── routes
20
+ └── user
21
+ ├── layout.tsx
22
+ └── layout.data.ts
23
+ ```
24
+ 在文件中定义以下代码:
25
+ ```ts title="routes/user/layout.data.ts"
26
+ import type { ActionFunction } from '@modern-js/runtime/router';
27
+
28
+ export const action: ActionFunction = ({ request }) => {
29
+ const newUser = await request.json();
30
+ const name = newUser.name;
31
+ return updateUserProfile(name);
32
+ }
33
+ ```
34
+
35
+ ```tsx title="routes/user/layout.tsx"
36
+ import {
37
+ useFetcher,
38
+ useLoaderData,
39
+ useParams,
40
+ Outlet
41
+ } from '@modern-js/runtime/router';
42
+
43
+ export default () => {
44
+ const userInfo = useLoaderData();
45
+ const { submit } = useFetcher();
46
+ const editUser = () => {
47
+ const newUser = {
48
+ name: 'Modern.js'
49
+ }
50
+ return submit(newUser, {
51
+ method: 'post',
52
+ encType: 'application/json',
53
+ })
54
+ }
55
+ return (
56
+ <div>
57
+ <button onClick={editUser}>edit user</button>
58
+ <div className="user-profile">
59
+ {userInfo}
60
+ </div>
61
+ <Outlet context={userInfo}></Outlet>
62
+ </div>
63
+ )
64
+ }
65
+ ```
66
+
67
+ 这里当执行 submit 后,会触发定义的 action 函数;在 action 函数中,可以通过 request (request.json,request.formData)获取提交的数据,获取数据后,再发送数据到服务端。
68
+
69
+ 而 action 函数执行完,会执行 loader 函数代码,并更新对应的数据和视图。
70
+
71
+ ![action flow](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-flow.png)
72
+
73
+
74
+
75
+ ## 为什么要提供 Data Action
76
+
77
+ Modern.js 中提供 Data Action 主要是为了使 UI 和服务器的状态能保持同步,通过这种方式可以减少状态管理的负担,
78
+ 传统的状态管理方式,会在客户端和远程分别持有状态:
79
+
80
+ ![traditional state manage](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-state-manage.png)
81
+
82
+ 而在 Modern.js 中,我们希望通过 Loader 和 Action 帮助开发者自动的同步客户端和服务端的状态:
83
+
84
+ ![state manage](https://lf3-static.bytednsdoc.com/obj/eden-cn/ulkl/ljhwZthlaukjlkulzlp/action-state-manage1.png)
85
+
86
+ 如果项目中组件共享的数据主要服务端的状态,则无需在项目引入客户端状态管理库,使用 Data Loader 请求数据,通过 [`useRouteLoaderData`](/guides/basic-features/data/data-fetch.md) 在子组件中共享数据,
87
+ 通过 Data Actino 修改和同步服务端的状态。
88
+
89
+
90
+
91
+ ## `action` 函数
92
+
93
+ 与 `loader` 函数一样,`action` 函数有两个入参,`params` 和 `request`:
94
+
95
+ ### `params`
96
+
97
+ 当路由文件通过 `[]` 时,会作为[动态路由](/guides/basic-features/routes#动态路由),动态路由片段会作为参数传入 `action` 函数:
98
+
99
+ ```tsx
100
+ // routes/user/[id]/page.data.ts
101
+ import { ActionFunctionArgs } from '@modern-js/runtime/router';
102
+
103
+ export const action = async ({ params }: ActionFunctionArgs) => {
104
+ const { id } = params;
105
+ const res = await fetch(`https://api/user/${id}`);
106
+ return res.json();
107
+ };
108
+ ```
109
+
110
+ 当访问 `/user/123` 时,`action` 函数的参数为 `{ params: { id: '123' } }`。
111
+
112
+
113
+ ### `request`
114
+
115
+ `request` 是一个 [Fetch Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) 实例。
116
+
117
+ 通过 `request`,可以在 action 函数中获取到客户端提交的数据,如 `request.json()`,`request.formData()`,`request.json()` 等,
118
+ 具体应该使用哪个 API,请参考[数据类型](#数据类型)。
119
+
120
+ ```tsx
121
+ // routes/user/[id]/page.data.ts
122
+ import { ActionFunctionArgs } from '@modern-js/runtime/router';
123
+
124
+ export const action = async ({ request }: ActionFunctionArgs) => {
125
+ const newUser = await request.json();
126
+ return updateUser(newUser);
127
+ };
128
+ ```
129
+
130
+ ### 返回值
131
+
132
+ `action` 函数的返回值可以是任何可序列化的内容,也可以是一个 [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) 实例,
133
+ 可以通过 [`useActionData`](https://reactrouter.com/en/main/hooks/use-action-data) 访问 response 中内容。
134
+
135
+
136
+ ## useSubmit 和 useFetcher
137
+
138
+ ### 区别
139
+
140
+ 你可以通过 [`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit) 或 [`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher) 调用 action,它们的区别是通过
141
+ `useSubmit` 调用 action,会触发浏览器的导航,通过 `useFetcher` 则不会触发浏览器的导航。
142
+
143
+ useSubmit:
144
+
145
+ ```ts
146
+ const submit = useSubmit();
147
+ submit(null, { method: "post", action: "/logout" });
148
+ ```
149
+
150
+ useFetcher:
151
+ ```ts
152
+ const { submit } = useFetcher();
153
+ submit(null, { method: "post", action: "/logout" });
154
+ ```
155
+
156
+ `submit` 函数有两个入参,`method` 和 `action`,`method` 相当于表单提交时的 `method`,大部分写入数据的场景下,`method` 可以传入 `post`,
157
+ `action` 用来指定触发哪个路由组件的 `action`,如果未传入 `action` 入参,默认会触发当前路由组件的 action,即 `user/page.tsx` 组件或子组件中执行 submit,
158
+ 会触发 `user/page.data.ts` 中定义的 action。
159
+
160
+ :::info
161
+ 这两个 API 更多的信息可参考相关文档:
162
+ - [`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit)
163
+ - [`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher)
164
+
165
+ :::
166
+
167
+
168
+ ### 数据类型
169
+
170
+ `submit` 函数的第一个入参,可以接受不同类型的值。
171
+ 如 `FormData`:
172
+ ```ts
173
+ let formData = new FormData();
174
+ formData.append("cheese", "gouda");
175
+ submit(formData);
176
+ // In the action, you can get the data by request.json
177
+ ```
178
+
179
+ 或 `URLSearchParams` 类型的值:
180
+ ```ts
181
+ let searchParams = new URLSearchParams();
182
+ searchParams.append("cheese", "gouda");
183
+ submit(searchParams);
184
+ // In the action, you can get the data by request.json
185
+ ```
186
+
187
+ 或任意 `URLSearchParams` 构造函数可接受的值
188
+ ```ts
189
+ submit("cheese=gouda&toasted=yes");
190
+ submit([
191
+ ["cheese", "gouda"],
192
+ ["toasted", "yes"],
193
+ ]);
194
+ // In the action, you can get the data by request.json
195
+ ```
196
+
197
+ 默认情况下,如果 `submit` 函数中的第一个入参是一个对象,对应的数据会被 encode 为 `formData`:
198
+
199
+ ```ts
200
+ submit(
201
+ { key: "value" },
202
+ {
203
+ method: "post",
204
+ encType: "application/x-www-form-urlencoded",
205
+ }
206
+ );
207
+
208
+ // In the action, you can get the data by request.formData
209
+ ```
210
+
211
+ 也可以指定为 json 编码:
212
+
213
+ ```tsx
214
+ submit(
215
+ { key: "value" },
216
+ { method: "post", encType: "application/json" }
217
+ );
218
+
219
+ submit('{"key":"value"}', {
220
+ method: "post",
221
+ encType: "application/json",
222
+ });
223
+
224
+ // In the action, you can get the data by request.json
225
+ ```
226
+
227
+ 或提交纯文本:
228
+ ```ts
229
+ submit("value", { method: "post", encType: "text/plain" });
230
+ // In the action, you can get the data by request.text
231
+ ```
232
+
233
+
234
+ ## CSR 和 SSR
235
+
236
+ 与 Data Loader 一样,SSR 项目中,Data Action 是在服务端执行的(框架会自动发请求触发 Data Action),而在 CSR 项目中,Data Action 是在客户端执行的。
@@ -164,7 +164,7 @@ export const handle = {
164
164
 
165
165
  ```ts title="routes/layout.ts"
166
166
  export default () => {
167
- const matches = useMatches;
167
+ const matches = useMatches();
168
168
  const breadcrumbs = matches.map(
169
169
  matchedRoute => matchedRoute?.handle?.breadcrumbName,
170
170
  );
@@ -189,7 +189,7 @@ export default () => {
189
189
 
190
190
  在组件中,可以通过 [useParams](/apis/app/runtime/router/router#useparams) 获取对应命名的参数。
191
191
 
192
- 在 loader 中,params 会作为 [loader](/guides/basic-features/data-fetch#loader-函数) 的入参,通过 `params.xxx` 可以获取。
192
+ 在 loader 中,params 会作为 [loader](/guides/basic-features/data/data-fetch#loader-函数) 的入参,通过 `params.xxx` 可以获取。
193
193
 
194
194
  ### 动态可选路由
195
195
 
@@ -209,7 +209,7 @@ export default () => {
209
209
 
210
210
  在组件中,可以通过 [useParams](/apis/app/runtime/router/router#useparams) 获取对应命名的参数。
211
211
 
212
- 在 loader 中,params 会作为 [loader](/guides/basic-features/data-fetch#loader-函数) 的入参,通过 `params.xxx` 可以获取。
212
+ 在 loader 中,params 会作为 [loader](/guides/basic-features/data/data-fetch#loader-函数) 的入参,通过 `params.xxx` 可以获取。
213
213
 
214
214
  ### 通配路由
215
215
 
@@ -352,12 +352,12 @@ Modern.js 建议必须有根 Layout 和根 Loading。
352
352
 
353
353
  ### 路由重定向
354
354
 
355
- 可以通过创建 [`Data Loader`](/guides/basic-features/data-fetch) 文件做路由的重定向,如有文件 `routes/user/page.tsx`,想对这个文件对应的路由做重定向,可以创建 `routes/user/page.loader.ts` 文件:
355
+ 可以通过创建 [`Data Loader`](/guides/basic-features/data/data-fetch) 文件做路由的重定向,如有文件 `routes/user/page.tsx`,想对这个文件对应的路由做重定向,可以创建 `routes/user/page.data.ts` 文件:
356
356
 
357
- ```ts title="routes/user/page.loader.ts"
357
+ ```ts title="routes/user/page.data.ts"
358
358
  import { redirect } from '@modern-js/runtime/router';
359
359
 
360
- export default () => {
360
+ export const loader () => {
361
361
  const user = await getUser();
362
362
  if (!user) {
363
363
  return redirect('/login');
@@ -504,7 +504,7 @@ export const init = (context: RuntimeContext) => {
504
504
  :::info
505
505
 
506
506
  - 该功能目前仅在 Webpack 项目中支持,Rspack 项目暂不支持。
507
- - 对数据的预加载目前只会预加载 SSR 项目中 [Data Loader](/guides/basic-features/data-fetch) 中返回的数据。
507
+ - 对数据的预加载目前只会预加载 SSR 项目中 [Data Loader](/guides/basic-features/data/data-fetch) 中返回的数据。
508
508
 
509
509
  :::
510
510
 
@@ -6,9 +6,9 @@ sidebar_position: 1
6
6
 
7
7
  通过本章节,你可以了解到 Modern.js 中的入口约定,以及如何自定义入口。
8
8
 
9
- ## 什么是入口(Entry)
9
+ ## 什么是入口
10
10
 
11
- **入口指的是一个页面的起始模块。**
11
+ **入口(Entry)指的是一个页面的起始模块。**
12
12
 
13
13
  在 Modern.js 项目中,每一个入口对应一个独立的页面,也对应一条服务端路由。默认情况下,Modern.js 会基于目录约定来自动确定页面的入口,同时也支持通过配置项来自定义入口。
14
14
 
@@ -56,7 +56,7 @@ Modern.js 初始化的项目是单入口的(SPA),项目结构如下:
56
56
 
57
57
  原本的入口代码被移动到了和 `package.json` 中 `name` 同名的目录下,并创建了 `new-entry` 入口目录。
58
58
 
59
- 执行 `pnpm run dev` 后,可以看到新增了一条名为 `/new-entry` 的路由,并且被迁移的代码路由并未发生变化。
59
+ 你可以执行 `pnpm run dev` 启动开发服务,此时可以看到新增了一条名为 `/new-entry` 的路由,并且原有页面的路由并未发生变化。
60
60
 
61
61
  :::tip
62
62
  Modern.js 会将与 `package.json` 文件中 `name` 字段同名的入口作为主入口,主入口的路由为 `/`,其他入口的路由为 `/{entryName}`。
@@ -76,7 +76,8 @@ import EntryMode from '@site-docs/components/entry-mode.mdx';
76
76
  默认情况下,Modern.js 启动项目前会对 `src/` 下的文件进行扫描,识别入口,并生成对应的服务端路由。
77
77
 
78
78
  :::tip
79
- 可以通过 [source.entriesDir](/configure/app/source/entries-dir) 修改页面的入口识别目录。
79
+ - 你可以通过 [source.entriesDir](/configure/app/source/entries-dir) 修改页面入口的识别目录。
80
+ - 如果你需要自定义入口,请参考 [自定义入口](#自定义入口)。
80
81
 
81
82
  :::
82
83
 
@@ -98,7 +99,7 @@ import EntryMode from '@site-docs/components/entry-mode.mdx';
98
99
 
99
100
  ### 框架模式入口
100
101
 
101
- 框架模式指需要使用 Modern.js 框架能力,例如 Router、SSR、一体化调用等。这类入口约定下,开发者定义的入口并不是真正的 webpack 编译入口。Modern.js 在启动时会生成一个封装过的入口,可以在 `node_modules/.modern/{entryName}/index.js` 找到真正的入口。
102
+ 框架模式指的是需要使用 Modern.js 的框架能力,例如嵌套路由、SSR、一体化调用等。这类入口约定下,开发者定义的入口并不是真正的编译入口。Modern.js 在启动时会生成一个封装过的入口,可以在 `node_modules/.modern/[entryName]/index.js` 找到真正的入口。
102
103
 
103
104
  #### 约定式路由
104
105
 
@@ -146,7 +147,7 @@ export default (App: React.ComponentType, bootstrap: () => void) => {
146
147
  // do something before bootstrap...
147
148
  initSomething().then(() => {
148
149
  bootstrap();
149
- })
150
+ });
150
151
  };
151
152
  ```
152
153
 
@@ -170,7 +171,9 @@ function render() {
170
171
  // runtime 的插件参数...
171
172
  })(App);
172
173
  if (IS_BROWSER) {
173
- customBootstrap(AppWrapper, () => bootstrap(AppWrapper, MOUNT_ID, root, ReactDOM));
174
+ customBootstrap(AppWrapper, () =>
175
+ bootstrap(AppWrapper, MOUNT_ID, root, ReactDOM),
176
+ );
174
177
  }
175
178
  return AppWrapper;
176
179
  }
@@ -182,9 +185,11 @@ export default AppWrapper;
182
185
 
183
186
  ### 构建模式入口
184
187
 
185
- 构建模式是指不使用任何 Modern.js 运行时的能力,完全由开发者自己定义项目 webpack 的入口。
188
+ 构建模式指的是不使用 Modern.js 自动生成的入口,而是完全由开发者自行定义页面的入口。
186
189
 
187
- 如果入口中存在 `index.[jt]sx` ,并且没有默认导出函数时,这时候该文件就是真正的 webpack 入口文件。这里和 [Create React App](https://github.com/facebook/create-react-app) 类似,需要自己将组件挂载到 DOM 节点、添加热更新代码等。例如:
190
+ 当入口目录中存在 `index.[jt]sx`,并且没有通过 `export default` 导出函数时,这类文件就会被识别为 webpack Rspack entry 模块。
191
+
192
+ 此时 Modern.js 不会自动生成入口代码,因此需要你自行将组件挂载到 DOM 节点上,例如:
188
193
 
189
194
  ```js title=src/index.jsx
190
195
  import React from 'react';
@@ -194,42 +199,39 @@ import App from './App';
194
199
  ReactDOM.render(<App />, document.getElementById('root'));
195
200
  ```
196
201
 
197
- Modern.js **不推荐**新项目使用这种方式,这种方式丧失了框架的一些能力,如 **`modern.config.js` 文件中的 `runtime` 配置将不会再生效**。但是在项目从其他框架迁移到 Modern.js,例如 CRA,或是自己手动搭建的 webpack 时,这种方式会非常有用。
202
+ 这种方式等价于开启 Modern.js [source.entries.disableMount](/configure/app/source/entries) 选项。当你使用这种方式时,**将无法使用 Modern.js 框架的运行时能力**,比如 modern.config.js 文件中的 `runtime` 配置将不会再生效。
198
203
 
199
- ## 使用配置指定入口
204
+ ## 自定义入口
200
205
 
201
- 大部分存量项目并不是按照 Modern.js 的目录结构来搭建的。如果要改成 Modern.js 约定的目录结构,会存在一定的迁移成本。
206
+ 在某些情况下,你可能需要自定义入口配置,而不是使用 Modern.js 提供的入口约定。
202
207
 
203
- 在这种情况下,除了使用文件约定生成入口外,你可以在 `modern.config.[jt]s` 中手动配置入口。
208
+ 比如你需要将一个非 Modern.js 项目迁移到 Modern.js,它并不是按照 Modern.js 的目录结构来搭建的。如果你要将它改成 Modern.js 约定的目录结构,可能会存在一定的迁移成本。这种情况下,你就可以使用自定义入口。
204
209
 
205
- ```ts title="modern.config.ts"
206
- export default defineConfig({
207
- source: {
208
- entries: {
209
- // 指定一个名称为 entry_customize 的新入口
210
- entry_customize: './src/home/test/index.ts',
211
- },
212
- // 禁用默认入口扫描
213
- disableDefaultEntries: true,
214
- },
215
- });
216
- ```
210
+ Modern.js 提供了以下配置项,你可以在 [modern.config.ts](/configure/app/usage) 中配置它们:
217
211
 
218
- ### 禁用默认入口扫描
212
+ - [source.entries](/configure/app/source/entries):用于设置自定义的入口对象。
213
+ - [source.disableDefaultEntries](/configure/app/source/disable-default-entries):用于关闭 Modern.js 默认的入口扫描行为。当你使用自定义入口时,项目的部分结构可能会恰巧命中 Modern.js 约定的目录结构,但你可能不希望 Modern.js 为你自动生成入口配置,开启该选项可以避免这个问题。
219
214
 
220
- 当使用自定义入口时,项目的部分结构可能恰巧命中了 Modern.js 的目录约定,但实际上这部分目录并不是真实的入口。
215
+ ### 示例
221
216
 
222
- Modern.js 提供了 `disableDefaultEntries` 配置,来禁用默认的入口扫描规则。当你需要自定义入口时,一般需要将 `disableDefaultEntries` 与 `entries` 结合使用。这样,一些存量项目可以在不修改目录结构的情况下,快速地进行迁移。
217
+ 下面是一个自定义入口的例子,你也可以查看相关配置项的文档来了解更多用法。
223
218
 
224
219
  ```ts title="modern.config.ts"
225
220
  export default defineConfig({
226
221
  source: {
222
+ entries: {
223
+ // 指定一个名为 'my-entry' 的入口
224
+ 'my-entry': {
225
+ // 入口模块的路径
226
+ entry: './src/my-page/index.tsx',
227
+ // 关闭 Modern.js 自动生成入口代码的行为
228
+ disableMount: true,
229
+ },
230
+ },
231
+ // 禁用入口扫描行为
227
232
  disableDefaultEntries: true,
228
233
  },
229
234
  });
230
235
  ```
231
236
 
232
- :::tip
233
- 详细用法请查看 [source.entries](/configure/app/source/entries) 和 [source.disableDefaultEntries](/configure/app/source/disable-default-entries)。
234
-
235
- :::
237
+ 注意,当你开启 `disableMount` 时,**将无法使用 Modern.js 框架的运行时能力**,比如 modern.config.ts 文件中的 `runtime` 配置将不会再生效。
@@ -92,7 +92,7 @@ $ pnpm run build
92
92
  > modern build
93
93
 
94
94
  info Staring production build...
95
- ready Client compiled in 50ms
95
+ ready Client compiled in 50 ms
96
96
  info Production file sizes:
97
97
 
98
98
  File Size Gzipped
@@ -1,5 +1,4 @@
1
1
  ---
2
- title: 扩展插件 Hook
3
2
  sidebar_position: 5
4
3
  ---
5
4
 
@@ -1,5 +1,4 @@
1
1
  ---
2
- title: Hook 列表
3
2
  sidebar_position: 8
4
3
  ---
5
4
 
@@ -1,7 +1,7 @@
1
1
  ---
2
- title: Hook 模型
3
2
  sidebar_position: 2
4
3
  ---
4
+
5
5
  # Hook 模型
6
6
 
7
7
  首先介绍一下 Modern.js 的基础的插件系统中的一些内容,包括 Hook 模型的工作方式、各个 Hook 模型的运行模式、Manager 的工作模式。
@@ -1,5 +1,4 @@
1
1
  ---
2
- title: 如何编写插件
3
2
  sidebar_position: 3
4
3
  ---
5
4
 
@@ -1,7 +1,7 @@
1
1
  ---
2
- title: 介绍
3
2
  sidebar_position: 1
4
3
  ---
4
+
5
5
  # 介绍
6
6
 
7
7
  ## Modern.js 插件系统
@@ -1,7 +1,7 @@
1
1
  ---
2
- title: 生命周期
3
2
  sidebar_position: 1
4
3
  ---
4
+
5
5
  # 生命周期
6
6
 
7
7
  Modern.js 应用具有完整的生命周期,包括 CLI、Server Side 和 Runtime 三个阶段。
@@ -1,5 +1,4 @@
1
1
  ---
2
- title: 插件 API
3
2
  sidebar_position: 6
4
3
  ---
5
4
 
@@ -79,26 +78,43 @@ interface NormalizedConfig {
79
78
  const useAppContext: () => IAppContext;
80
79
 
81
80
  interface IAppContext {
81
+ /** 当前项目的根目录 */
82
82
  appDirectory: string;
83
+ /** 源代码目录 */
84
+ srcDirectory: string;
85
+ /** 构建产出输出目录 */
86
+ distDirectory: string;
87
+ /** 公共模块目录 */
88
+ sharedDirectory: string;
89
+ /** 框架临时文件输出目录 */
90
+ internalDirectory: string;
91
+ /** node_modules 目录 */
92
+ nodeModulesDirectory: string;
93
+ /** 配置文件路径 */
83
94
  configFile: string | false;
95
+ /** 当前机器的 IPv4 地址 */
84
96
  ip?: string;
97
+ /** 开发服务器的端口号 */
85
98
  port?: number;
86
- distDirectory: string;
99
+ /** 当前项目 package.json 的 name */
87
100
  packageName: string;
88
- srcDirectory: string;
89
- sharedDirectory: string;
90
- nodeModulesDirectory: string;
91
- internalDirectory: string;
92
- plugins: {
93
- cli?: any;
94
- server?: any;
95
- }[];
101
+ /** 当前注册的插件 */
102
+ plugins: any[];
103
+ /** 页面入口信息 */
96
104
  entrypoints: Entrypoint[];
105
+ /** 服务端路由信息 */
97
106
  serverRoutes: ServerRoute[];
98
- htmlTemplates: HtmlTemplates;
107
+ /** 当前项目类型 */
108
+ toolsType?: 'app-tools' | 'module-tools' | 'monorepo-tools';
109
+ /** 当前使用的打包工具类型 */
110
+ bundlerType?: 'webpack' | 'rspack' | 'esbuild';
99
111
  }
100
112
  ```
101
113
 
114
+ :::tip
115
+ AppContext 中的部分字段是动态设置的,会随着程序的运行而变化。因此,当插件在不同的时机读取字段时,可能会获取到不同的值。
116
+ :::
117
+
102
118
  ### useHookRunners
103
119
 
104
120
  用于获取 Hooks 的执行器,并触发特定的 Hook 执行。
@@ -116,3 +132,7 @@ export const myPlugin = (): CliPlugin => ({
116
132
  },
117
133
  });
118
134
  ```
135
+
136
+ :::tip
137
+ 请尽量避免执行框架内置的 hooks,否则可能会导致框架内部的运行逻辑出错。
138
+ :::
@@ -1,7 +1,7 @@
1
1
  ---
2
- title: 插件之间的关系
3
2
  sidebar_position: 4
4
3
  ---
4
+
5
5
  # 插件之间的关系
6
6
 
7
7
  Modern.js 的插件配置对象提供了一系列的字段,用于控制插件顺序、互斥等能力,可用的字段如下:
@@ -129,13 +129,8 @@ sidebar_position: 3
129
129
  选项:
130
130
 
131
131
  - Web 应用 -- mwa
132
-
133
- - Web 应用(测试)-- mwa_test
134
-
135
132
  - Npm 模块 -- module
136
133
 
137
- - Npm 模块(内部)-- inner_module
138
-
139
134
  ### packageName
140
135
 
141
136
  问题:请填写子项目名称
@@ -44,12 +44,12 @@ defineConfig(App, {
44
44
  return [
45
45
  {
46
46
  name: 'Table',
47
- entry: 'http://localhost:8001',
47
+ entry: 'http://localhost:8081',
48
48
  // activeWhen: '/table'
49
49
  },
50
50
  {
51
51
  name: 'Dashboard',
52
- entry: 'http://localhost:8002',
52
+ entry: 'http://localhost:8082',
53
53
  // activeWhen: '/dashboard'
54
54
  },
55
55
  ];
@@ -29,23 +29,9 @@ pnpm run new
29
29
  ```
30
30
  ? 请选择你想创建的工程类型 (Use arrow keys)
31
31
  ❯ Web 应用
32
- Web 应用(测试)
33
32
  Npm 模块
34
- Npm 模块(内部)
35
33
  ```
36
34
 
37
- :::info
38
- 「应用」与「应用(测试)」都是「应用」类型的项目,区别是「应用」类型的子项目会创建在 `./apps` 目录下,而 「应用(测试)」类型的子项目会创建在 `./examples` 目录下。
39
-
40
- :::
41
-
42
- :::info
43
- 「模块」与「模块(内部)」都是「模块」类型的项目,区别之一是「模块」类型的子项目会创建在 `./packages` 目录下,而「模块(内部)」类型的子项目会创建在 `./features` 目录下。
44
-
45
- 对于「模块」类型的子项目允许被发布到外部(例如 npm),而对于「模块(内部)」的子项目则可以在应用项目中直接使用其源码(该特性是「模块」项目不具备的,应用项目对于「模块(内部)」子项目做了特殊处理),因此这类子项目不需要发布到外部。
46
-
47
- :::
48
-
49
35
  然后根据不同的需求选择对应的类型项目选项,选择之后便开始出现对应子项目类型的问题和选项。例如选择「应用」后会出现:
50
36
 
51
37
  ```