插件基础
重要提示:Yumeri 的插件系统在 3.0 之后继续增强,关键变化包括更灵活的依赖声明、自动安装缺失插件,以及命名插件实例的配置方式。
编写你的插件
ts
import { Context, Config } from 'yumeri'
export const depend = ['database', 'logger']
export const optional = ['cache']
export async function apply(ctx: Context, config: Config) {
ctx.route('/foo').action(async (session) => {
session.respond('Hello', 'plain')
})
}ts
import { Session, Context } from 'yumeri'
import { Plugin, Get, Inject } from '@yumerijs/decorator'
export const depend = ['database']
@Plugin
export default class MyPlugin {
@Inject('database')
db: any
@Get('/foo')
async action(session: Session) {
session.respond('Hello', 'plain')
}
}必需依赖与可选依赖
插件入口文件中最重要的声明通常是:
ts
export const depend = ['database', 'logger']
export const optional = ['cache']含义如下:
depend:必需依赖,若缺失则插件无法正常加载。optional:可选依赖,若存在就尽量加载;若不存在则不阻塞插件本身的加载。
在 3.0 以后,Loader 会优先处理 depend 与 optional,使插件装配过程更稳定,也能处理“非核心能力缺失但功能可降级”的场景。
依赖管理
如果你的插件依赖于其他插件提供的组件,必须在入口文件中导出一个 depend 数组:
ts
export const depend = ['database', 'logger']每个字符串对应所依赖的组件名称。即使在装饰器模式下使用了 @Inject,这个 depend 也依然是必需的,因为它决定了插件加载顺序,并确保依赖项在实例化前已经就绪。
插件配置与实例化
插件可以通过 config 导出定义结构:
ts
import { Schema } from 'yumeri'
export const config = Schema.object({
enabled: Schema.boolean('是否启用').default(true),
timeout: Schema.number('超时时间').default(3000),
})加载时,Yumeri 会把配置对象注入给插件,并自动填充缺失的默认值。更多细节请见 配置构型。
命名插件实例
3.0 之后,配置文件中的插件不再只支持传统的 { "plugin-name": { ... } } 形式,还支持命名实例方式:
json
{
"plugins": {
"demo": {
"module": "yumeri-plugin-demo",
"config": {
"enabled": true
}
},
"~demo-disabled": {
"module": "yumeri-plugin-demo",
"config": {
"enabled": false
}
}
}
}其中:
- 未加
~:表示正常启用的插件 - 加
~:表示该插件实例被禁用,但配置仍保留,便于后续重新启用 module:指定真实的插件模块名称config:插件实例配置
这种形式允许同一插件在同一应用中存在多个实例,并分别配置不同参数。
配置形式对照
| 形式 | 含义 | 适用场景 |
|---|---|---|
"demo": { ... } | 传统插件配置 | 单实例插件 |
"demo": { "module": "...", "config": {...} } | 实例化配置 | 同插件多实例 |
"~demo" | 禁用状态保留配置 | 预留配置但暂不启用 |
缺失插件自动安装
Yumeri 3.0 引入了更友好的插件缺失处理:
- 如果配置中某个插件未安装,Loader 可检测到这个情况。
- 可通过
--auto-install参数自动执行安装。 - 安装成功后需要重启进程以加载新插件。
启动命令示例:
bash
yumeri --auto-install
yumeri --config ./config/my-yumeri.json这使得开发和部署时的插件依赖管理更加顺畅,尤其适合团队协作和自动化环境。
依赖装配的真实顺序
Loader 会按以下顺序处理插件:
- 读取配置中的插件列表
- 解析每个插件的
depend和optional - 先处理必需依赖,确保核心能力可用
- 再尽量装载可选依赖
- 若插件缺失,则按配置选择是否安装
- 最终完成插件上下文、路由和组件注册
这意味着:
- 你不是手动决定“谁先加载”
- Loader 会根据依赖图决定加载顺序
- 某些插件即使不是绝对必要,也可以在存在时自动注入
~ 禁用实例的意义
命名实例配置不是语法糖,它解决的是“同一个插件的不同实例需要不同参数”的问题:
json
{
"plugins": {
"demo": { "module": "yumeri-plugin-demo", "config": { "enabled": true } },
"~demo-safe": { "module": "yumeri-plugin-demo", "config": { "enabled": false } }
}
}这一点很适合:
- 多环境配置
- 预留配置并暂时关闭
- 灰度发布和切换
- 多租户或多主题部署
缺失插件自动安装的真实场景
在团队协作或 CI 环境中,插件依赖可能会遗漏。Loader 的设计就是把这种情况尽量降到“开发者不需要手工补全所有依赖”的程度:
bash
yumeri --auto-install在命令行里启动应用时,如果发现缺失依赖,框架会尝试自动安装,然后要求重启进程以完成加载。
最佳实践
- 把真正“必需”的能力放进
depend,把“增强型/降级型”能力放进optional。 - 始终为插件定义
config,避免让配置散落在代码中。 - 对复杂配置使用
Schema.object(),并设置合理默认值。 - 在团队或 CI 环境中使用
--auto-install以减少插件遗漏问题。 - 同一插件的多个实例要用命名实例配置,而不是伪造多个不同插件名。
