4.2 KiB
Phase 0:基础设施骨架
目标
建好管道,不改现有功能。验证编译通过 + API 可调用。
不包含:无 UI 变化、无真实插件注册、无设置面板。
文件清单与实施顺序
Step 1:核心接口定义
新建 internal/plugin/plugin.go
内容:PluginID、PluginSource、PluginMetadata、PluginCapability、Plugin 接口、TabProvider、FilePreviewHandler、PreviewInfo、TabDef、CoreServices 接口定义。
依赖:无
Step 2:适配器(避免方法泄漏)
新建 internal/plugin/adapter.go
内容:adapter 结构体实现 CoreServices 接口的 6 个方法。构造函数 NewAdapter(app *App) CoreServices。
关键设计:不在 App 上直接实现 CoreServices(会导致 6 个内部方法被 Wails v3 自动暴露为前端 API),而是通过独立 adapter 封装。
依赖:Step 1
Step 3:Tab 注册表
新建 internal/plugin/tab_registry.go
内容:
TabRegistrystruct(mu + entries map)- Register(冲突检测)、GetByTabKey、GetAllDefinitions(按 Order 排序)、GetAllProviders、Count
依赖:Step 1
Step 4:预览注册表
新建 internal/plugin/preview_registry.go
内容:
PreviewRegistrystruct(mu + handlers 切片,按 priority 降序)- Register(自动排序)、Resolve(遍历匹配第一个 canHandle)、GetAllHandlers、Count
依赖:Step 1
Step 5:PluginManager
新建 internal/plugin/manager.go
内容:
Managerstruct(plugins map + core + tabReg + previewReg + ctx + initialized)- NewManager、Register(自动分发到子注册表 + 回滚)、InitAll、StartByTabKey
- GetPluginInfos、ResolvePreview(附加 PluginID 到响应)、GetTabDefinitions、Shutdown
依赖:Step 1 ~ 4 全部
Step 6:前端类型定义
新建 frontend/src/plugin/types.ts
内容:PluginCapability enum、PluginMetadata、TabPluginDefinition、FilePreviewHandlerDefinition、RenderConfig 接口。
依赖:无
Step 7:前端注册中心
新建 frontend/src/plugin/registry.ts
内容:
- Vue reactive state(tabPlugins Map + previewHandlers 数组)
- Tab API:registerTabPlugin / getTabComponent / getAllTabDefinitions / hasTabPlugin
- Preview API:registerPreviewHandler(按 priority 插入)/ resolvePreviewHandler / getAllPreviewHandlers
- 调试工具:getRegistryStats
依赖:Step 6
Step 8:集成到 App
修改 app.go
改动点:
- 新增字段:
pluginMgr *plugin.Manager(在mu字段之后) - ServiceStartup 中(步骤 4 之后):初始化 pluginMgr
fmt.Println("[启动] 初始化插件管理器...") a.pluginMgr = plugin.NewManager(plugin.NewAdapter(a)) - ServiceShutdown 末尾:关闭 pluginMgr
if a.pluginMgr != nil { a.pluginMgr.Shutdown() } - 新增绑定方法(Wails v3 自动暴露前端):
GetPluginInfos() ([]map[string]interface{}, error)— 返回空数组或插件列表ResolvePreview(req ResolvePreviewRequest) (map[string]interface{}, error)— 解析文件预览处理器ResolvePreviewRequest{Filename string}请求结构体
依赖:Step 5
验证方案
编译验证
go build ./internal/plugin/
go build .
cd frontend && npx vue-tsc --noEmit
运行时验证
| # | 操作 | 预期结果 |
|---|---|---|
| V1 | 运行应用 | 日志出现 [启动] 初始化插件管理器... |
| V2 | 关闭应用 | 日志出现 [插件管理器] 已关闭 |
| V3 | DevTools: GetPluginInfos() |
返回 {success:true, data:[]} |
| V4 | DevTools: ResolvePreview({filename:'test'}) |
返回 {success:false, message:"no preview handler..."} |
| V5 | 前端 import registry | 无 TS 错误 |
边界情况
| 场景 | 预期行为 |
|---|---|
| pluginMgr 为 nil 调用 GetPluginInfos | 返回空数组,不 panic |
| pluginMgr 为 nil 调用 ResolvePreview | 返回 success:false,不 panic |
| TabRegistry.Register 同一 TabKey 两次 | 返回冲突错误 |
| PreviewRegistry.Resolve 无匹配文件 | 返回 nil, "" |
| Manager.Shutdown 无插件注册 | 正常返回 nil |