生命周期与依赖
插件引导不是简单遍历数组。宿主会先确定启用集合、检查依赖和冲突,再按顺序注册能力。
引导顺序
bootstrapPlugins() 当前按下面流程执行:
- 设置自定义
pluginStateProvider。 - 初始化宿主 UI 配置。
- 保存本次传入的运行时插件清单。
- 按
order升序排序。 - 过滤
enabled: false和禁用列表中的插件。 - 检查
dependsOn是否都在启用集合中。 - 检查插件、路由和菜单冲突。
- 依次注册路由、菜单和语言包。
- 依次执行插件
install()。 - 把 Router 安装到 Vue 应用。
任一步抛出错误都会中断应用引导。
注册顺序
ts
const corePlugin: AdminPlugin = {
id: 'report-core',
name: '报表基础插件',
version: '1.0.0',
order: 10
}
const auditPlugin: AdminPlugin = {
id: 'report-audit',
name: '报表审计插件',
version: '1.0.0',
order: 20,
dependsOn: ['report-core']
}order 决定实际执行顺序。dependsOn 只检查依赖是否启用,不会自动进行拓扑排序。
因此,依赖插件应该使用更小的 order,确保它的 install() 先执行。
安装钩子
ts
const reportPlugin: AdminPlugin = {
id: 'report-plugin',
name: '报表插件',
version: '1.0.0',
async install(app, context) {
app.component('ReportBadge', ReportBadge)
if (context.enabledPluginIds.includes('workspace-plugin')) {
await setupWorkspaceIntegration()
}
}
}适合放在 install() 中的工作:
- 注册插件级全局组件。
- 注册自定义布局。
- 根据已启用插件建立集成。
- 执行应用级、一次性的异步初始化。
不建议放入:
- 普通页面数据请求。
- 每次进入路由都要执行的逻辑。
- 依赖 DOM 已经挂载的操作。
- 无法释放的全局事件或定时器。
install() 可以返回 Promise,宿主会等待它完成。
清理钩子
协议定义了 dispose(context):
ts
const reportPlugin: AdminPlugin = {
id: 'report-plugin',
name: '报表插件',
version: '1.0.0',
dispose(context) {
console.log('dispose', context.enabledPluginIds)
}
}当前 bootstrapPlugins() 不会自动调用 dispose()。插件启停通过保存状态并刷新应用生效,不支持在当前页面中完整热卸载。
如果项目实现自己的重引导或微前端卸载流程,需要主动调用对应插件的 dispose()。
启停状态
插件是否进入启用集合取决于:
plugin.enabled !== false- 插件 ID 不在
pluginStateProvider返回的禁用列表中
状态写入后,刷新应用才能重新执行完整引导。具体见安装与启停。
依赖错误
下面的配置会在启动时失败:
ts
const auditPlugin: AdminPlugin = {
id: 'report-audit',
name: '报表审计插件',
version: '1.0.0',
dependsOn: ['report-core']
}
await bootstrapPlugins({
app,
router,
plugins: [auditPlugin] // 缺少 report-core
})错误会指出缺少的插件 ID。
冲突错误
引导阶段会阻止:
- 重复插件 ID。
- 与宿主或其他插件重复的路由路径。
- 重复的路由名称。
- 重复的菜单路径。
冲突不会自动覆盖。修复命名空间后再重新启动应用。
依赖设计建议
- 只依赖稳定、明确的插件能力。
- 不要用
dependsOn表达单纯的菜单排序。 - 基础插件使用较小
order,依赖方使用较大order。 - 避免 A 依赖 B、B 又依赖 A。
install()内仍要检查外部服务或配置是否可用。- 插件管理页禁用插件前,应检查所有启用中的依赖方。
下一步
继续阅读调试与发布。
