@modern-js/main-doc 2.65.4 → 2.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/en/apis/app/hooks/config/_meta.json +1 -0
- package/docs/en/apis/app/hooks/config/favicon.mdx +29 -0
- package/docs/en/apis/app/hooks/config/icon.mdx +3 -30
- package/docs/en/community/blog/v2-release-note.mdx +1 -1
- package/docs/en/configure/app/plugins.mdx +2 -2
- package/docs/en/configure/app/tools/esbuild.mdx +1 -1
- package/docs/en/configure/app/tools/swc.mdx +1 -1
- package/docs/en/plugin/_meta.json +8 -7
- package/docs/en/plugin/cli-plugins/_meta.json +1 -1
- package/docs/en/plugin/cli-plugins/api.mdx +617 -0
- package/docs/en/plugin/cli-plugins/life-cycle.mdx +139 -0
- package/docs/en/plugin/cli-plugins/migration.mdx +98 -0
- package/docs/en/plugin/introduction.mdx +119 -47
- package/docs/en/plugin/official/_meta.json +12 -0
- package/docs/en/plugin/official/cli-plugins/_meta.json +1 -0
- package/docs/en/plugin/official/cli-plugins.mdx +6 -0
- package/docs/en/plugin/official/rsbuild-plugins.mdx +3 -0
- package/docs/en/plugin/plugin-system.mdx +237 -0
- package/docs/en/plugin/runtime-plugins/_meta.json +1 -0
- package/docs/en/plugin/runtime-plugins/api.mdx +165 -0
- package/docs/en/plugin/runtime-plugins/life-cycle.mdx +29 -0
- package/docs/en/plugin/runtime-plugins/migration.mdx +101 -0
- package/docs/en/plugin/server-plugins/api.mdx +3 -0
- package/docs/en/plugin/server-plugins/life-cycle.mdx +3 -0
- package/docs/zh/apis/app/hooks/config/_meta.json +1 -0
- package/docs/zh/apis/app/hooks/config/favicon.mdx +29 -0
- package/docs/zh/apis/app/hooks/config/icon.mdx +3 -30
- package/docs/zh/community/blog/v2-release-note.mdx +1 -1
- package/docs/zh/configure/app/plugins.mdx +2 -2
- package/docs/zh/configure/app/tools/esbuild.mdx +1 -1
- package/docs/zh/configure/app/tools/swc.mdx +1 -1
- package/docs/zh/plugin/_meta.json +8 -7
- package/docs/zh/plugin/cli-plugins/_meta.json +1 -1
- package/docs/zh/plugin/cli-plugins/api.mdx +617 -0
- package/docs/zh/plugin/cli-plugins/life-cycle.mdx +139 -0
- package/docs/zh/plugin/cli-plugins/migration.mdx +98 -0
- package/docs/zh/plugin/introduction.mdx +92 -20
- package/docs/zh/plugin/official/_meta.json +12 -0
- package/docs/zh/plugin/official/cli-plugins/_meta.json +1 -0
- package/docs/zh/plugin/official/cli-plugins.mdx +6 -0
- package/docs/zh/plugin/official/rsbuild-plugins.mdx +3 -0
- package/docs/zh/plugin/plugin-system.mdx +239 -0
- package/docs/zh/plugin/runtime-plugins/_meta.json +1 -0
- package/docs/zh/plugin/runtime-plugins/api.mdx +166 -0
- package/docs/zh/plugin/runtime-plugins/life-cycle.mdx +29 -0
- package/docs/zh/plugin/runtime-plugins/migration.mdx +101 -0
- package/docs/zh/plugin/server-plugins/api.mdx +3 -0
- package/docs/zh/plugin/server-plugins/life-cycle.mdx +3 -0
- package/i18n.json +4 -0
- package/package.json +4 -4
- package/src/components/Footer/index.tsx +1 -1
- package/src/components/Mermaid/index.tsx +60 -0
- package/src/components/Mermaid/style.scss +221 -0
- package/docs/en/plugin/cli-plugins.mdx +0 -6
- package/docs/en/plugin/plugin-system/_meta.json +0 -10
- package/docs/en/plugin/plugin-system/extend.mdx +0 -163
- package/docs/en/plugin/plugin-system/hook-list.mdx +0 -711
- package/docs/en/plugin/plugin-system/hook.mdx +0 -188
- package/docs/en/plugin/plugin-system/implement.mdx +0 -243
- package/docs/en/plugin/plugin-system/introduction.mdx +0 -95
- package/docs/en/plugin/plugin-system/lifecycle.mdx +0 -16
- package/docs/en/plugin/plugin-system/plugin-api.mdx +0 -138
- package/docs/en/plugin/plugin-system/relationship.mdx +0 -119
- package/docs/en/plugin/rsbuild-plugins.mdx +0 -3
- package/docs/zh/plugin/cli-plugins.mdx +0 -6
- package/docs/zh/plugin/plugin-system/_meta.json +0 -10
- package/docs/zh/plugin/plugin-system/extend.mdx +0 -163
- package/docs/zh/plugin/plugin-system/hook-list.mdx +0 -715
- package/docs/zh/plugin/plugin-system/hook.mdx +0 -173
- package/docs/zh/plugin/plugin-system/implement.mdx +0 -250
- package/docs/zh/plugin/plugin-system/introduction.mdx +0 -94
- package/docs/zh/plugin/plugin-system/lifecycle.mdx +0 -16
- package/docs/zh/plugin/plugin-system/plugin-api.mdx +0 -138
- package/docs/zh/plugin/plugin-system/relationship.mdx +0 -119
- package/docs/zh/plugin/rsbuild-plugins.mdx +0 -4
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-bff.mdx +0 -0
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-ssg.mdx +0 -0
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-swc.mdx +0 -0
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-tailwind.mdx +0 -0
- /package/docs/en/plugin/{rsbuild-plugins → official/rsbuild-plugins}/_meta.json +0 -0
- /package/docs/en/plugin/{rsbuild-plugins → official/rsbuild-plugins}/plugin-esbuild.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-bff.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-ssg.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-swc.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-tailwind.mdx +0 -0
- /package/docs/zh/plugin/{rsbuild-plugins → official/rsbuild-plugins}/_meta.json +0 -0
- /package/docs/zh/plugin/{rsbuild-plugins → official/rsbuild-plugins}/plugin-esbuild.mdx +0 -0
@@ -1,173 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 2
|
3
|
-
---
|
4
|
-
|
5
|
-
# Hook 模型
|
6
|
-
|
7
|
-
首先介绍一下 Modern.js 的基础的插件系统中的一些内容,包括 Hook 模型的工作方式、各个 Hook 模型的运行模式、Manager 的工作模式。
|
8
|
-
|
9
|
-
每种 Hook 模型都是独立的,可以独立管理运行函数。
|
10
|
-
|
11
|
-
## 基础工作方式
|
12
|
-
|
13
|
-
先以 Pipeline 为例,简单介绍一下 Hook 模型的工作方式。先看一个简单的例子:
|
14
|
-
|
15
|
-
```ts
|
16
|
-
import { createPipeline } from '@modern-js/plugin';
|
17
|
-
|
18
|
-
// 1. 创建
|
19
|
-
const pipeline = createPipeline<number, number>();
|
20
|
-
|
21
|
-
// 2. 添加函数
|
22
|
-
pipeline.use((count, next) => {
|
23
|
-
return next(count + 1);
|
24
|
-
});
|
25
|
-
pipeline.use((count, next) => {
|
26
|
-
return count * 2;
|
27
|
-
});
|
28
|
-
|
29
|
-
// 3. 执行
|
30
|
-
pipeline.run(1); // 4
|
31
|
-
pipeline.run(5); // 12
|
32
|
-
```
|
33
|
-
|
34
|
-
在这个例子中,创建了一个 `Pipeline<number, number>` 类型的 Pipeline(L3),这意味着运行它的时候,你需要传入一个 `number`,然后你会得到一个 `number`,而这个模型管理的函数的类型是:
|
35
|
-
|
36
|
-
```ts
|
37
|
-
(count: number, next: (nextCount: number) => number) => number;
|
38
|
-
```
|
39
|
-
|
40
|
-
这里全是 `number`,是因为我们创建的是 `Pipeline<number, number>` ,如果创建的是 `Pipeline<number, string>` 则运行它入参是 `number`,返回值是 `string`,对应管理的函数的类型会是:
|
41
|
-
|
42
|
-
```ts
|
43
|
-
(count: number, next: (nextCount: number) => string) => string;
|
44
|
-
```
|
45
|
-
|
46
|
-
创建好 Pipeline 之后,可以通过 `use` 添加函数(L5、L8),需要注意的是,添加的顺序就是他们默认的运行顺序,在这些函数中,你可以对 `count` 进行处理、返回一个值,如果你调用了 `next` 函数,则会运行后面的函数,即如果你添加了三个函数: `A`、`B`、`C`,如果你在 `A` 中调用 `next` 那么就会运行 `B`,同样的,如果你在 `B` 中调用 `next` 那么就会运行 `C`,而在上面的例子中,添加的第一个函数(L5)就运行了 `next`,所以这里就会运行第二个函数(L8),并且运行的返回值就是 第二个函数的返回值,如果在第一个函数中没有调用 `next`,直接返回,例如:
|
47
|
-
|
48
|
-
```ts
|
49
|
-
import { createPipeline } from '@modern-js/plugin';
|
50
|
-
|
51
|
-
// 1. 创建
|
52
|
-
const pipeline = createPipeline<number, number>();
|
53
|
-
|
54
|
-
// 2. 添加函数
|
55
|
-
pipeline.use((count, next) => {
|
56
|
-
return count + 1;
|
57
|
-
});
|
58
|
-
pipeline.use((count, next) => {
|
59
|
-
return count * 2;
|
60
|
-
});
|
61
|
-
|
62
|
-
// 3. 执行
|
63
|
-
pipeline.run(1); // 2
|
64
|
-
pipeline.run(5); // 6
|
65
|
-
```
|
66
|
-
|
67
|
-
则在运行 Pipeline 的时候就不会运行第二个函数,那么 Pipeline 的运行结果则就是第一个函数的返回值。
|
68
|
-
|
69
|
-
最后,运行 Pipeline 的方式也显而易见就是调用 `pipeline.run` 。
|
70
|
-
|
71
|
-
## 不同 Hook 模型的区别
|
72
|
-
|
73
|
-
上面这部分就是 Pipeline 整体的一个工作模式的描述,其他的 Hook 模型的工作模式基本也是这样,主要的区别点,是函数类型、执行顺序,参数。
|
74
|
-
|
75
|
-
### Pipeline
|
76
|
-
|
77
|
-
上面的例子就是以 Pipeline 为例描述的,这里就不赘述了,在 Pipeline 这个大类中,提供了两个小类:Sync 和 Async,顾名思义,它们的区别就是管理的函数的类型是 Sync 的还是 Async 的。
|
78
|
-
|
79
|
-
:::info
|
80
|
-
当 Pipeline 中没有函数或者所有函数都调用了 `next` 函数,则就需要在运行的时候提供:
|
81
|
-
|
82
|
-
```ts
|
83
|
-
pipeline(
|
84
|
-
{},
|
85
|
-
{
|
86
|
-
onLast: () => {
|
87
|
-
// do something
|
88
|
-
},
|
89
|
-
},
|
90
|
-
);
|
91
|
-
```
|
92
|
-
|
93
|
-
:::
|
94
|
-
|
95
|
-
### Waterfall
|
96
|
-
|
97
|
-
这种模型顾名思义,他的特点就是参数的顺序递交,即前面一个函数的返回值,将会成为下一个函数的入参,我们也用一个例子来看一下:
|
98
|
-
|
99
|
-
```ts
|
100
|
-
import { createWaterfall } from '@modern-js/plugin';
|
101
|
-
|
102
|
-
// 1. 创建
|
103
|
-
const waterfall = createWaterfall<number>();
|
104
|
-
|
105
|
-
// 2. 添加函数
|
106
|
-
waterfall.use(count => {
|
107
|
-
return count + 1;
|
108
|
-
});
|
109
|
-
waterfall.use(count => {
|
110
|
-
return count * 2;
|
111
|
-
});
|
112
|
-
|
113
|
-
// 3. 执行
|
114
|
-
waterfall.run(1); // 4
|
115
|
-
waterfall.run(5); // 12
|
116
|
-
```
|
117
|
-
|
118
|
-
这个例子中,创建了一个类型为 `Waterfall<number> `,即这个模型执行的入参和返回值是一样的,这个例子中都是 `number`,而它管理的函数的类型是:
|
119
|
-
|
120
|
-
```ts
|
121
|
-
(count: number) => number;
|
122
|
-
```
|
123
|
-
|
124
|
-
可能简单看这个例子感觉和上面的 Pipeline 功能一样,那需要注意的是,首先这里 Waterfall 管理的函数没有 next 函数作为第二个参数,所以它无法在函数内部通过调用 next 来先运行之后添加的函数,从而修改运行的顺序,其次这里的运行的入参的类型和返回值的类型必须是一样的(而 Pipeline 可以不一样)。
|
125
|
-
|
126
|
-
同样的,在 Waterfall 这个大类中,也提供了 Sync 和 Async 的小类,分别对应 Sync 和 Async 的函数。
|
127
|
-
|
128
|
-
### Workflow
|
129
|
-
|
130
|
-
这种 Hook 模型与上面两种 Hook 模型的区别是,没有那么强的前后参数返回值递交的概念,在这个模型中,每个函数都是基于同样的入参,相对独立运行的,通过一个例子简单看一下:
|
131
|
-
|
132
|
-
```ts
|
133
|
-
import { createWorkflow } from '@modern-js/plugin';
|
134
|
-
|
135
|
-
// 1. 创建
|
136
|
-
const workflow = createWorkflow<number, number>();
|
137
|
-
|
138
|
-
// 2. 添加函数
|
139
|
-
workflow.use(count => {
|
140
|
-
return count + 1;
|
141
|
-
});
|
142
|
-
workflow.use(count => {
|
143
|
-
return count * 2;
|
144
|
-
});
|
145
|
-
|
146
|
-
// 3. 执行
|
147
|
-
workflow.run(1); // [2, 2]
|
148
|
-
workflow.run(5); // [6, 10]
|
149
|
-
```
|
150
|
-
|
151
|
-
在这个例子中,添加了两个函数,所以运行的结果就是这两个函数运行的结果形成的一个数组。
|
152
|
-
|
153
|
-
虽然这种模型中没有那么强的前后参数返回值递交的概念,但依旧有执行顺序的区别,在 Workflow 这个大类中,提供了三个小类:Sync、Async、Parallel。他们之间的区别就是函数的执行顺序,当然默认的都是按照添加顺序执行,而在 Sync、Async 则是强制按照添加顺序执行,而 Parallel 则是 Async 模式的一个变体,即它使用的是 `Promise.all` 来执行所有函数,而 Async 则会 `await` 前面的函数运行结束。
|
154
|
-
|
155
|
-
## Hook 模型对比
|
156
|
-
|
157
|
-
<div style={{ width: "100%", overflowX: "scroll" }}>
|
158
|
-
<div style={{ width: "150%" }}>
|
159
|
-
|
160
|
-
| | 函数类型 | 执行顺序 | 函数参数来源 | 执行返回值来源 | 倾向处理的任务类型 | 函数 TS 类型 |
|
161
|
-
| ---------------- | ---------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------ |
|
162
|
-
| Pipeline | Sync | 默认执行第一个添加的函数,可以通过 next 调用之后添加的函数 | 第一个函数的参数来源是运行的参数,之后的函数的参数来源是,前一个函数向 next 函数传递的参数 | 第一个函数的返回值 | <ul><li>需要修改初始参数</li><li>需要修改函数执行顺序</li></ul> | `(input: I, next: Next<I, O>) => O` |
|
163
|
-
| AsyncPipeline | Sync/Async | 默认执行第一个添加的函数,可以通过 next 调用之后添加的函数 | 第一个函数的参数来源是运行的参数,之后的函数的参数来源是,前一个函数向 next 函数传递的参数 | 第一个函数的返回值 | <ul><li>需要修改初始参数</li><li>需要修改函数执行顺序</li></ul> | `(input: I, next: AsyncNext<I, O>) => O | Promise<O>` |
|
164
|
-
| WaterFall | Sync | 一直顺序执行 | 第一个函数的参数来源是运行的参数,之后的函数的参数来源是,前一个函数的返回值 | 最后一个函数的返回值 | <ul><li>需要修改初始参数</li><li>不需要修改函数执行顺序</li></ul> | `(I: I) => I` |
|
165
|
-
| AsyncWaterFall | Sync/Async | 一直顺序执行 | 第一个函数的参数来源是运行的参数,之后的函数的参数来源是,前一个函数的返回值 | 最后一个函数的返回值 | <ul><li>需要修改初始参数</li><li>不需要修改函数执行顺序</li></ul> | `(I: I) => I | Promise<I>` |
|
166
|
-
| Workflow | Sync | 一直顺序执行 | 所有函数的入参都是运行的参数 | 所有函数返回值形成的数组 | <ul><li>不需要修改初始参数</li><li>不需要修改函数执行顺序</li></ul> | `(I: I) => O` |
|
167
|
-
| AsyncWorkflow | Sync/Async | 一直顺序执行 | 所有函数的入参都是运行的参数 | 所有函数返回值形成的数组 | <ul><li>不需要修改初始参数</li><li>不需要修改函数执行顺序</li></ul> | `(I: I) => O | Promise<O>` |
|
168
|
-
| ParallelWorkFlow | Sync/Async | 异步执行 | 所有函数的入参都是运行的参数 | 所有函数返回值形成的数组 | <ul><li>不需要修改初始参数</li><li>不关心执行顺序</li></ul> | `(I: I) => O | Promise<O>` |
|
169
|
-
|
170
|
-
</div>
|
171
|
-
</div>
|
172
|
-
|
173
|
-
Workflow、Waterfall 其实都是 Pipeline 的变体,Pipeline 可以通过特定的写法来实现 Workflow、Waterfall,但都较为麻烦,有许多隐形的约定。为了方便使用,提供了这两种变体来满足这种特殊场景。
|
@@ -1,250 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 3
|
3
|
-
---
|
4
|
-
|
5
|
-
# 如何编写插件
|
6
|
-
|
7
|
-
上一小节介绍了 Modern.js 插件的 Hook 模型,这一小节介绍如何编写插件。
|
8
|
-
|
9
|
-
## 实现插件
|
10
|
-
|
11
|
-
Modern.js 插件是一个对象,对象包含以下属性:
|
12
|
-
|
13
|
-
- `name`: 插件的名称,唯一标识符。
|
14
|
-
- `setup`: 插件初始化函数,只会执行一次。setup 函数可以返回一个 Hooks 对象,Modern.js 会在特定的时机执行这些 Hooks。
|
15
|
-
|
16
|
-
```ts
|
17
|
-
const myPlugin = {
|
18
|
-
name: 'my-plugin',
|
19
|
-
|
20
|
-
setup() {
|
21
|
-
// 执行一些初始化逻辑
|
22
|
-
const foo = '1';
|
23
|
-
|
24
|
-
// 返回一个 Hooks 对象
|
25
|
-
return {
|
26
|
-
afterBuild: () => {
|
27
|
-
// 在构建完成后执行逻辑
|
28
|
-
},
|
29
|
-
};
|
30
|
-
},
|
31
|
-
};
|
32
|
-
```
|
33
|
-
|
34
|
-
另外,在插件中,允许配置与其他插件的执行顺序。详情可以参考[插件关系](/plugin/plugin-system/relationship)。
|
35
|
-
|
36
|
-
### 插件类型
|
37
|
-
|
38
|
-
Modern.js 支持多种工程开发,如应用开发(Modern.js Framework), 模块开发(Modern.js Module)等。
|
39
|
-
|
40
|
-
为了兼顾不同工程开发的差异和通性,Modern.js 将插件如下图进行组织:
|
41
|
-
|
42
|
-

|
43
|
-
|
44
|
-
从图可以看出,Modern.js 将插件大致分为两类:
|
45
|
-
|
46
|
-
1. 通用插件: 插件只会包含一些基础的 Hooks
|
47
|
-
|
48
|
-
2. 工程插件: 不同的工程开发会在通用插件的基础上扩展出自己的 Hooks, Config 等类型。
|
49
|
-
|
50
|
-
使用 TypeScript 时,可以引入内置的 `CliPlugin` 等类型,为插件提供正确的类型推导。
|
51
|
-
|
52
|
-
```ts
|
53
|
-
import type { CliPlugin } from '@modern-js/core';
|
54
|
-
|
55
|
-
const myPlugin: CliPlugin = {
|
56
|
-
name: 'my-plugin',
|
57
|
-
|
58
|
-
setup() {
|
59
|
-
const foo = '1';
|
60
|
-
|
61
|
-
return {
|
62
|
-
afterBuild: () => {
|
63
|
-
// 在构建完成后执行逻辑
|
64
|
-
},
|
65
|
-
};
|
66
|
-
},
|
67
|
-
};
|
68
|
-
```
|
69
|
-
|
70
|
-
上述代码为通用插件,只包含一些基础的 Hooks。 Modern.js 支持通过泛型对插件的定义进行扩展:
|
71
|
-
|
72
|
-
```ts
|
73
|
-
import type { CliPlugin, AppTools } from '@modern-js/app-tools';
|
74
|
-
|
75
|
-
const myPlugin: CliPlugin<AppTools> = {
|
76
|
-
name: 'my-plugin',
|
77
|
-
|
78
|
-
setup() {
|
79
|
-
const foo = '1';
|
80
|
-
|
81
|
-
return {
|
82
|
-
afterBuild: () => {
|
83
|
-
// 在构建完成后执行逻辑
|
84
|
-
},
|
85
|
-
};
|
86
|
-
},
|
87
|
-
};
|
88
|
-
```
|
89
|
-
|
90
|
-
如果仔细观察 `AppTools` 这个类型,可以发现 `AppTools` 由 3 种类型构成.
|
91
|
-
|
92
|
-
```ts
|
93
|
-
type AppTools = {
|
94
|
-
hooks: AppToolsHooks;
|
95
|
-
userConfig: AppToolsUserConfig;
|
96
|
-
normalizedConfig: AppToolsNormalizedConfig;
|
97
|
-
};
|
98
|
-
```
|
99
|
-
|
100
|
-
当编写插件时,插件通过泛型扩展在不同的基础上扩展自己的 Hooks 等类型:
|
101
|
-
|
102
|
-
```ts
|
103
|
-
// 通用插件上扩展
|
104
|
-
import type { CliPlugin } from '@modern-js/core';
|
105
|
-
import type { MyPluginHook } from 'xxx';
|
106
|
-
|
107
|
-
const myPlugin: CliPlugin<{ hooks: MyPluginHook }> = {};
|
108
|
-
```
|
109
|
-
|
110
|
-
```ts
|
111
|
-
// 在 @modern-js/app-tools 基础上扩展
|
112
|
-
import type { CliPlugin, AppTools } from '@modern-js/app-tools';
|
113
|
-
import type { MyPluginHook } from 'xxx';
|
114
|
-
|
115
|
-
const myPlugin: CliPlugin<AppTools & { hooks: MyPluginHook }> = {};
|
116
|
-
```
|
117
|
-
|
118
|
-
详细说明,请参考 [扩展 Hook](/plugin/plugin-system/extend)。
|
119
|
-
|
120
|
-
### 插件配置项
|
121
|
-
|
122
|
-
**建议将插件写成函数的形式**,使插件能通过函数入参来接收配置项:
|
123
|
-
|
124
|
-
```ts
|
125
|
-
import type { CliPlugin } from '@modern-js/core';
|
126
|
-
|
127
|
-
type MyPluginOptions = {
|
128
|
-
foo: string;
|
129
|
-
};
|
130
|
-
|
131
|
-
const myPlugin = (options: MyPluginOptions): CliPlugin => ({
|
132
|
-
name: 'my-plugin',
|
133
|
-
|
134
|
-
setup() {
|
135
|
-
console.log(options.foo);
|
136
|
-
},
|
137
|
-
});
|
138
|
-
```
|
139
|
-
|
140
|
-
### 插件 API
|
141
|
-
|
142
|
-
插件的 `setup` 函数会接收一个 api 入参,你可以调用 api 上提供的一些方法来获取到配置、应用上下文等信息。
|
143
|
-
|
144
|
-
```ts
|
145
|
-
import type { CliPlugin } from '@modern-js/core';
|
146
|
-
|
147
|
-
export const myPlugin = (): CliPlugin => ({
|
148
|
-
name: 'my-plugin',
|
149
|
-
|
150
|
-
setup(api) {
|
151
|
-
// 获取应用原始配置
|
152
|
-
const config = api.useConfigContext();
|
153
|
-
// 获取应用运行上下文
|
154
|
-
const appContext = api.useAppContext();
|
155
|
-
// 获取解析之后的最终配置
|
156
|
-
const resolvedConfig = api.useResolvedConfigContext();
|
157
|
-
},
|
158
|
-
});
|
159
|
-
```
|
160
|
-
|
161
|
-
插件 API 的详细说明,请参考 [Plugin API](/plugin/plugin-system/plugin-api)。
|
162
|
-
|
163
|
-
### 异步 setup
|
164
|
-
|
165
|
-
CLI 插件的 setup 可以是一个异步函数,在初始化过程中执行异步逻辑。
|
166
|
-
|
167
|
-
```ts
|
168
|
-
import type { CliPlugin } from '@modern-js/core';
|
169
|
-
|
170
|
-
export const myPlugin = (): CliPlugin => ({
|
171
|
-
name: 'my-plugin',
|
172
|
-
|
173
|
-
async setup(api) {
|
174
|
-
await doSomething();
|
175
|
-
},
|
176
|
-
});
|
177
|
-
```
|
178
|
-
|
179
|
-
注意,只有当前插件的 setup 异步函数执行完毕,才会继续执行下一个插件的 setup 函数。因此,你需要避免在 setup 函数中进行耗时过长的异步操作,防止影响 CLI 启动性能。
|
180
|
-
|
181
|
-
## 添加插件
|
182
|
-
|
183
|
-
自定义插件的使用方式可以查看:[plugins (框架插件)](/configure/app/plugins)。下面会介绍 Modern.js 中推荐的插件实现方法。
|
184
|
-
|
185
|
-
### 开发本地插件
|
186
|
-
|
187
|
-
本地插件推荐写在 `config/plugin` 目录下,并通过 `export default` 导出:
|
188
|
-
|
189
|
-
```ts title=config/plugin/myPlugin.ts
|
190
|
-
import type { CliPlugin } from '@modern-js/core';
|
191
|
-
|
192
|
-
export const myPlugin = (): CliPlugin => ({
|
193
|
-
name: 'my-plugin',
|
194
|
-
|
195
|
-
setup() {
|
196
|
-
// 插件初始化
|
197
|
-
},
|
198
|
-
});
|
199
|
-
```
|
200
|
-
|
201
|
-
然后在 `modern.config.ts` 中注册对应的插件:
|
202
|
-
|
203
|
-
```ts title="modern.config.ts"
|
204
|
-
import { defineConfig } from '@modern-js/app-tools';
|
205
|
-
import { myPlugin } from './config/plugin/myPlugin';
|
206
|
-
|
207
|
-
export default defineConfig({
|
208
|
-
plugins: [myPlugin()],
|
209
|
-
});
|
210
|
-
```
|
211
|
-
|
212
|
-
### 在 npm 上发布插件
|
213
|
-
|
214
|
-
如果你需要将 Modern.js 插件发布到 npm,推荐使用 [Modern.js Module](https://modernjs.dev/module-tools) 来管理和构建。
|
215
|
-
|
216
|
-
首先创建一个空的 Modern.js Module 项目,调整 npm 包名称:
|
217
|
-
|
218
|
-
```json
|
219
|
-
{
|
220
|
-
"name": "my-plugin"
|
221
|
-
...
|
222
|
-
}
|
223
|
-
```
|
224
|
-
|
225
|
-
然后新建对应的插件文件:
|
226
|
-
|
227
|
-
```ts title=src/index.ts
|
228
|
-
import type { CliPlugin } from '@modern-js/core';
|
229
|
-
|
230
|
-
export const myPlugin = (): CliPlugin => ({
|
231
|
-
name: 'my-plugin',
|
232
|
-
|
233
|
-
setup() {
|
234
|
-
// 插件初始化
|
235
|
-
},
|
236
|
-
});
|
237
|
-
```
|
238
|
-
|
239
|
-
发布之后,安装到需要使用的项目 `pnpm add my-plugin`,这里以一个应用项目为例,然后在 `modern.config.ts` 中添加:
|
240
|
-
|
241
|
-
```ts title="modern.config.ts"
|
242
|
-
import { defineConfig } from '@modern-js/app-tools';
|
243
|
-
import { myPlugin } from 'my-plugin';
|
244
|
-
|
245
|
-
export default defineConfig({
|
246
|
-
plugins: [myPlugin()],
|
247
|
-
});
|
248
|
-
```
|
249
|
-
|
250
|
-
如果你发现目前 Modern.js 存在无法满足的场景,欢迎通过**编写自定义插件的方式**来一起建设 Modern.js 生态。
|
@@ -1,94 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 1
|
3
|
-
---
|
4
|
-
|
5
|
-
# 介绍
|
6
|
-
|
7
|
-
## Modern.js 插件系统
|
8
|
-
|
9
|
-
Modern.js 提供了一套拥有完整生命周期的插件系统。插件可用于扩展项目运行、请求、渲染等不同阶段功能,
|
10
|
-
|
11
|
-
## 使用方式
|
12
|
-
|
13
|
-
插件需要在配置文件中显式注册才能够生效,当需要为 Modern.js 添加插件时,可以将它配置到 [plugins](/configure/app/plugins.html) 字段中:
|
14
|
-
|
15
|
-
```ts title="edenx.config.ts"
|
16
|
-
// an example for bff
|
17
|
-
import { appTools, defineConfig } from '@modern-js/app-tools';
|
18
|
-
import { bffPlugin } from '@modern-js/plugin-bff';
|
19
|
-
|
20
|
-
export default defineConfig({
|
21
|
-
plugins: [appTools(), bffPlugin()],
|
22
|
-
});
|
23
|
-
```
|
24
|
-
|
25
|
-
:::note
|
26
|
-
注意,该配置仅支持添加 Modern.js 插件,无法添加 Webpack 插件。
|
27
|
-
:::
|
28
|
-
|
29
|
-
## 官方插件
|
30
|
-
|
31
|
-
Modern.js 提供了一系列官方插件,并与 Modern.js 生成器结合。所有的官方插件功能,都可以通过执行 `new` 命令开启。例如当需要开启 BFF 功能时:
|
32
|
-
|
33
|
-
```bash
|
34
|
-
$ npx modern new
|
35
|
-
? 请选择你想要的操作 启用可选功能
|
36
|
-
? 请选择功能名称 (Use arrow keys)
|
37
|
-
启用 「Tailwind CSS」 支持
|
38
|
-
❯ 启用「BFF」功能
|
39
|
-
启用「微前端」模式
|
40
|
-
```
|
41
|
-
|
42
|
-
完成选择后,Modern.js 生成器会自动安装对应的插件和三方依赖,安装完成后可以看到:
|
43
|
-
|
44
|
-
```bash
|
45
|
-
[INFO] 依赖自动安装成功
|
46
|
-
|
47
|
-
[INFO] 安装插件依赖成功!请添加如下代码至 modern.config.ts :
|
48
|
-
|
49
|
-
import { bffPlugin } from '@modern-js/plugin-bff';
|
50
|
-
import { expressPlugin } from '@modern-js/plugin-express';
|
51
|
-
|
52
|
-
export default defineConfig({
|
53
|
-
...,
|
54
|
-
plugins: [..., bffPlugin(), expressPlugin()],
|
55
|
-
});
|
56
|
-
```
|
57
|
-
|
58
|
-
此时,可以按照控制台的输出,将插件添加到配置文件中。
|
59
|
-
|
60
|
-
## 插件系统组成
|
61
|
-
|
62
|
-
Modern.js 插件系统主要分为三个部分:Hook 模型、管理器,上下文共享机制。
|
63
|
-
|
64
|
-
- Hook 模型用于确定当前 Hook 的执行逻辑。
|
65
|
-
- 管理器用于控制 Hook 的执行与调度。
|
66
|
-
- 上下文共享机制用于在不同 Hook 间传递信息。
|
67
|
-
|
68
|
-
目前 Modern.js 提供几种不同的 Hook 模型:**Pipeline、Waterfall、Workflow**。
|
69
|
-
|
70
|
-
:::note
|
71
|
-
后续章节详细介绍各个模型的执行方式。
|
72
|
-
:::
|
73
|
-
|
74
|
-
Modern.js 基于 Hook 模型暴露了三套插件:CLI、Runtime、Server。
|
75
|
-
|
76
|
-
其中 CLI 插件是 Modern.js 中主要的运行流程控制模型,Modern.js 中绝大部分功能都是主要通过这一套模型运行的。Runtime 插件主要负责处理 React 组件渲染逻辑。Server 插件主要用于对服务端的生命周期以及用户请求的控制。
|
77
|
-
|
78
|
-
## 插件可以做什么
|
79
|
-
|
80
|
-
Modern.js 的所有功能都是通过这套插件实现的,这意味着 Modern.js 中的所有能力是都对开发者开放的。开发者可以通过编写插件来扩展更多功能,适配复杂场景,包括但不限于:
|
81
|
-
|
82
|
-
- 注册命令
|
83
|
-
- 修改 Modern.js 配置、配置校验 Schema
|
84
|
-
- 修改编译时的 Webpack/Babel/Less/Sass/Tailwind CSS/... 配置
|
85
|
-
- 修改运行时需要渲染的 React 组件、Element
|
86
|
-
- 修改页面路由
|
87
|
-
- 修改服务器路由
|
88
|
-
- 自定义控制台输出
|
89
|
-
- 自定义动态 HTML 模版
|
90
|
-
- 自定义 Node.js 服务器框架
|
91
|
-
- 自定义 React 组件客户端/服务器端渲染
|
92
|
-
- ...
|
93
|
-
|
94
|
-
当 Modern.js 暂时没有覆盖到所需要的功能或场景时,可以开发一个自定义插件,来实现适配特殊场景的相关功能。
|
@@ -1,16 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 1
|
3
|
-
---
|
4
|
-
|
5
|
-
# 生命周期
|
6
|
-
|
7
|
-
Modern.js 应用具有完整的生命周期,包括 CLI、Server Side 和 Runtime 三个阶段。
|
8
|
-
|
9
|
-
目前 Modern.js 大致的生命周期如下:
|
10
|
-
|
11
|
-
:::note
|
12
|
-
其中粉色框的矩形代表 Modern.js 提供的插件钩子,淡黄色底色椭圆代表与下一个阶段的连接点。
|
13
|
-
|
14
|
-
:::
|
15
|
-
|
16
|
-

|
@@ -1,138 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 6
|
3
|
-
---
|
4
|
-
|
5
|
-
# 插件 API
|
6
|
-
|
7
|
-
插件的 `setup` 函数会接收一个 `api` 入参,你可以调用 api 上提供的一些方法来获取到配置、应用上下文等信息。
|
8
|
-
|
9
|
-
```ts
|
10
|
-
import type { CliPlugin } from '@modern-js/core';
|
11
|
-
|
12
|
-
export const myPlugin = (): CliPlugin => ({
|
13
|
-
name: 'my-plugin',
|
14
|
-
|
15
|
-
setup(api) {
|
16
|
-
// 获取应用原始配置
|
17
|
-
const config = api.useConfigContext();
|
18
|
-
// 获取应用运行上下文
|
19
|
-
const appContext = api.useAppContext();
|
20
|
-
// 获取解析之后的最终配置
|
21
|
-
const resolvedConfig = api.useResolvedConfigContext();
|
22
|
-
},
|
23
|
-
});
|
24
|
-
```
|
25
|
-
|
26
|
-
## API
|
27
|
-
|
28
|
-
### useConfigContext
|
29
|
-
|
30
|
-
用于获取应用原始配置。
|
31
|
-
|
32
|
-
```ts
|
33
|
-
const useConfigContext: () => UserConfig;
|
34
|
-
|
35
|
-
interface UserConfig {
|
36
|
-
source?: SourceConfig;
|
37
|
-
output?: OutputConfig;
|
38
|
-
server?: ServerConfig;
|
39
|
-
deploy?: DeployConfig;
|
40
|
-
// ...other fields
|
41
|
-
}
|
42
|
-
```
|
43
|
-
|
44
|
-
具体配置字段的意义请参考 [配置](/configure/app/usage)。
|
45
|
-
|
46
|
-
:::tip
|
47
|
-
该方法获取到的是只读配置,不可修改。如果需要修改配置,请使用 [config hook](/plugin/plugin-system/hook-list.html#config)。
|
48
|
-
:::
|
49
|
-
|
50
|
-
### useResolvedConfigContext
|
51
|
-
|
52
|
-
用于获取被解析、合并之后的最终配置。
|
53
|
-
|
54
|
-
```ts
|
55
|
-
const useResolvedConfigContext: () => NormalizedConfig;
|
56
|
-
|
57
|
-
interface NormalizedConfig {
|
58
|
-
source: NormalizedSourceConfig;
|
59
|
-
output: NormalizedOutputConfig;
|
60
|
-
server: NormalizedServerConfig;
|
61
|
-
deploy: NormalizedDeployConfig;
|
62
|
-
_raw: UserConfig; // 原始配置对象
|
63
|
-
// ...other fields
|
64
|
-
}
|
65
|
-
```
|
66
|
-
|
67
|
-
配置字段的完整内容请参考 [配置](/configure/app/usage)。
|
68
|
-
|
69
|
-
:::tip
|
70
|
-
该方法获取到的是只读配置,不可修改。如果需要修改配置,请使用 [config hook](/plugin/plugin-system/hook-list.html#config)。
|
71
|
-
:::
|
72
|
-
|
73
|
-
### useAppContext
|
74
|
-
|
75
|
-
用于获取应用运行上下文。
|
76
|
-
|
77
|
-
```ts
|
78
|
-
const useAppContext: () => IAppContext;
|
79
|
-
|
80
|
-
interface IAppContext {
|
81
|
-
/** 当前项目的根目录 */
|
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
|
-
/** 配置文件路径 */
|
94
|
-
configFile: string | false;
|
95
|
-
/** 当前机器的 IPv4 地址 */
|
96
|
-
ip?: string;
|
97
|
-
/** 开发服务器的端口号 */
|
98
|
-
port?: number;
|
99
|
-
/** 当前项目 package.json 的 name */
|
100
|
-
packageName: string;
|
101
|
-
/** 当前注册的插件 */
|
102
|
-
plugins: any[];
|
103
|
-
/** 页面入口信息 */
|
104
|
-
entrypoints: Entrypoint[];
|
105
|
-
/** 服务端路由信息 */
|
106
|
-
serverRoutes: ServerRoute[];
|
107
|
-
/** 当前项目类型 */
|
108
|
-
toolsType?: 'app-tools' | 'module-tools';
|
109
|
-
/** 当前使用的打包工具类型 */
|
110
|
-
bundlerType?: 'webpack' | 'rspack' | 'esbuild';
|
111
|
-
}
|
112
|
-
```
|
113
|
-
|
114
|
-
:::tip
|
115
|
-
AppContext 中的部分字段是动态设置的,会随着程序的运行而变化。因此,当插件在不同的时机读取字段时,可能会获取到不同的值。
|
116
|
-
:::
|
117
|
-
|
118
|
-
### useHookRunners
|
119
|
-
|
120
|
-
用于获取 Hooks 的执行器,并触发特定的 Hook 执行。
|
121
|
-
|
122
|
-
```ts
|
123
|
-
import type { CliPlugin } from '@modern-js/core';
|
124
|
-
|
125
|
-
export const myPlugin = (): CliPlugin => ({
|
126
|
-
name: 'my-plugin',
|
127
|
-
|
128
|
-
async setup(api) {
|
129
|
-
const hookRunners = api.useHookRunners();
|
130
|
-
// 触发 afterBuild Hook
|
131
|
-
await hookRunners.afterBuild();
|
132
|
-
},
|
133
|
-
});
|
134
|
-
```
|
135
|
-
|
136
|
-
:::tip
|
137
|
-
请尽量避免执行框架内置的 hooks,否则可能会导致框架内部的运行逻辑出错。
|
138
|
-
:::
|