@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.
- package/docs/en/apis/app/hooks/src/routes.mdx +1 -1
- package/docs/en/components/debug-app.mdx +1 -1
- package/docs/en/components/turtorials-example-list.mdx +2 -0
- package/docs/en/configure/app/source/entries.mdx +7 -6
- package/docs/en/guides/advanced-features/bff/sdk.mdx +119 -0
- package/docs/en/guides/advanced-features/rspack-start.mdx +1 -1
- package/docs/en/guides/advanced-features/ssr.mdx +17 -17
- package/docs/en/guides/basic-features/data/_category_.json +4 -0
- package/docs/en/guides/basic-features/{data-fetch.mdx → data/data-fetch.mdx} +35 -27
- package/docs/en/guides/basic-features/data/data-write.mdx +241 -0
- package/docs/en/guides/basic-features/routes.mdx +7 -7
- package/docs/en/guides/concept/entries.mdx +31 -30
- package/docs/en/guides/get-started/quick-start.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/extend.mdx +0 -1
- package/docs/en/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
- package/docs/en/guides/topic-detail/framework-plugin/hook.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/implement.mdx +1 -2
- package/docs/en/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
- package/docs/en/guides/topic-detail/framework-plugin/relationship.mdx +2 -2
- package/docs/en/guides/topic-detail/generator/new/config.md +0 -5
- package/docs/en/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
- package/docs/en/tutorials/first-app/c05-loader.mdx +2 -2
- package/docs/en/tutorials/first-app/c06-model.mdx +4 -4
- package/docs/en/tutorials/first-app/c07-container.mdx +3 -3
- package/docs/en/tutorials/foundations/introduction.mdx +3 -2
- package/docs/zh/apis/app/hooks/src/routes.mdx +1 -1
- package/docs/zh/components/debug-app.mdx +1 -1
- package/docs/zh/components/micro-runtime-config.mdx +2 -2
- package/docs/zh/components/turtorials-example-list.mdx +2 -0
- package/docs/zh/configure/app/source/entries.mdx +7 -6
- package/docs/zh/guides/advanced-features/bff/sdk.mdx +119 -0
- package/docs/zh/guides/advanced-features/rspack-start.mdx +1 -1
- package/docs/zh/guides/advanced-features/ssr.mdx +16 -16
- package/docs/zh/guides/basic-features/data/_category_.json +4 -0
- package/docs/zh/guides/basic-features/{data-fetch.mdx → data/data-fetch.md} +31 -27
- package/docs/zh/guides/basic-features/data/data-write.mdx +236 -0
- package/docs/zh/guides/basic-features/routes.mdx +7 -7
- package/docs/zh/guides/concept/entries.mdx +34 -32
- package/docs/zh/guides/get-started/quick-start.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/extend.mdx +0 -1
- package/docs/zh/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
- package/docs/zh/guides/topic-detail/framework-plugin/hook.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/implement.mdx +0 -1
- package/docs/zh/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
- package/docs/zh/guides/topic-detail/framework-plugin/relationship.mdx +1 -1
- package/docs/zh/guides/topic-detail/generator/new/config.md +0 -5
- package/docs/zh/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
- package/docs/zh/guides/topic-detail/monorepo/create-sub-project.mdx +0 -14
- package/docs/zh/guides/topic-detail/monorepo/sub-project-interface.mdx +7 -43
- package/docs/zh/tutorials/first-app/c05-loader.mdx +2 -2
- package/docs/zh/tutorials/first-app/c06-model.mdx +3 -3
- package/docs/zh/tutorials/first-app/c07-container.mdx +3 -3
- package/docs/zh/tutorials/foundations/introduction.mdx +3 -2
- 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
|
+

|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
## 为什么要提供 Data Action
|
76
|
+
|
77
|
+
Modern.js 中提供 Data Action 主要是为了使 UI 和服务器的状态能保持同步,通过这种方式可以减少状态管理的负担,
|
78
|
+
传统的状态管理方式,会在客户端和远程分别持有状态:
|
79
|
+
|
80
|
+

|
81
|
+
|
82
|
+
而在 Modern.js 中,我们希望通过 Loader 和 Action 帮助开发者自动的同步客户端和服务端的状态:
|
83
|
+
|
84
|
+

|
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.
|
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.
|
357
|
+
```ts title="routes/user/page.data.ts"
|
358
358
|
import { redirect } from '@modern-js/runtime/router';
|
359
359
|
|
360
|
-
export
|
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
|
-
##
|
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
|
-
|
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
|
-
|
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
|
-
|
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, () =>
|
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
|
-
|
188
|
+
构建模式指的是不使用 Modern.js 自动生成的入口,而是完全由开发者自行定义页面的入口。
|
186
189
|
|
187
|
-
|
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
|
202
|
+
这种方式等价于开启 Modern.js 的 [source.entries.disableMount](/configure/app/source/entries) 选项。当你使用这种方式时,**将无法使用 Modern.js 框架的运行时能力**,比如 modern.config.js 文件中的 `runtime` 配置将不会再生效。
|
198
203
|
|
199
|
-
##
|
204
|
+
## 自定义入口
|
200
205
|
|
201
|
-
|
206
|
+
在某些情况下,你可能需要自定义入口配置,而不是使用 Modern.js 提供的入口约定。
|
202
207
|
|
203
|
-
|
208
|
+
比如你需要将一个非 Modern.js 项目迁移到 Modern.js,它并不是按照 Modern.js 的目录结构来搭建的。如果你要将它改成 Modern.js 约定的目录结构,可能会存在一定的迁移成本。这种情况下,你就可以使用自定义入口。
|
204
209
|
|
205
|
-
|
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
|
-
|
215
|
+
### 示例
|
221
216
|
|
222
|
-
|
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
|
-
|
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` 配置将不会再生效。
|
@@ -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
|
-
|
99
|
+
/** 当前项目 package.json 的 name */
|
87
100
|
packageName: string;
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
+
:::
|
@@ -44,12 +44,12 @@ defineConfig(App, {
|
|
44
44
|
return [
|
45
45
|
{
|
46
46
|
name: 'Table',
|
47
|
-
entry: 'http://localhost:
|
47
|
+
entry: 'http://localhost:8081',
|
48
48
|
// activeWhen: '/table'
|
49
49
|
},
|
50
50
|
{
|
51
51
|
name: 'Dashboard',
|
52
|
-
entry: 'http://localhost:
|
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
|
```
|