Back to Prompt Optimizer

桌面应用架构重构计划

docs/archives/103-desktop-architecture/refactor-plan.md

2.10.29.8 KB
Original Source

桌面应用架构重构计划

概述

本文档记录了桌面应用从当前脆弱的"底层fetch代理"架构迁移到稳定、可维护的"高层服务代理"架构的完整重构计划。

问题分析

当前架构问题

  1. 存储机制不兼容:在 Node.js 环境(Electron 主进程)中错误地使用了 localStorage,导致 StorageError: 获取存储项失败
  2. 底层代理脆弱性:通过模拟 fetch API 进行 IPC 通信,AbortSignalHeaders 对象序列化问题频发
  3. 模块导入问题TypeError: createModelManager is not a function 表明 CommonJS 导入解析失败
  4. 架构职责不清:主进程和渲染进程职责混乱,难以维护和调试

目标架构

  • 主进程作为后端:运行所有 @prompt-optimizer/core 核心服务,使用 Node.js 兼容的存储方案
  • 渲染进程作为前端:纯粹的 Vue UI,通过代理类与主进程通信
  • 高层 IPC 接口:稳定的服务级别通信,取代底层 fetch 代理
  • 统一存储策略:为不同环境提供合适的存储实现

实施计划

阶段一:核心改造 (core 包)

1. 创建 MemoryStorageProvider

  • 文件: packages/core/src/services/storage/memoryStorageProvider.ts (已完成)
  • 目标: 为 Node.js 环境和测试环境提供内存存储实现
  • 要求:
    • 实现 IStorageProvider 接口 ✅
    • 使用 Map 对象模拟内存存储 ✅
    • 支持序列化/反序列化以模拟真实存储行为 ✅
  • 测试结果: 所有14个测试通过 ✅

2. 集成新的存储提供者 ✅

  • 文件: packages/core/src/services/storage/factory.ts
  • 操作: 在 StorageFactory.create() 中添加 'memory' 选项 ✅
  • 文件: packages/core/src/index.ts
  • 操作: 导出 MemoryStorageProvider 类 ✅

3. 创建工厂函数 ✅

  • 文件: packages/core/src/services/storage/factory.ts
  • 操作: 在 StorageFactory.create() 中添加 'memory' 选项 ✅
  • 文件: packages/core/src/index.ts
  • 操作: 导出 MemoryStorageProvider 类 ✅

阶段二:后端改造 (主进程)

4. 清理并重构主进程

  • 文件: packages/desktop/main.js
  • 删除内容:
    • 所有 ipcMain.handle('api-fetch', ...) 处理器
    • 模拟 Response 对象的辅助代码
    • 复杂的 AbortSignalHeaders 处理逻辑
  • 新增内容:
    • 导入所有核心服务和工厂函数
    • 使用 StorageFactory.create('memory') 创建存储实例
    • 实例化所有核心服务 (ModelManager, TemplateManager, etc.)

5. 建立高层服务 IPC 接口

  • 文件: packages/desktop/main.js
  • 接口清单:
    javascript
    // 模型管理
    ipcMain.handle('models:getAllModels', () => modelManager.getAllModels());
    ipcMain.handle('models:saveModel', (e, model) => modelManager.saveModel(model));
    ipcMain.handle('models:deleteModel', (e, key) => modelManager.deleteModel(key));
    ipcMain.handle('models:enableModel', (e, key) => modelManager.enableModel(key));
    ipcMain.handle('models:disableModel', (e, key) => modelManager.disableModel(key));
    
    // 模板管理
    ipcMain.handle('templates:getAllTemplates', () => templateManager.getAllTemplates());
    ipcMain.handle('templates:saveTemplate', (e, template) => templateManager.saveTemplate(template));
    ipcMain.handle('templates:deleteTemplate', (e, id) => templateManager.deleteTemplate(id));
    
    // 历史记录
    ipcMain.handle('history:getHistory', () => historyManager.getHistory());
    ipcMain.handle('history:addHistory', (e, entry) => historyManager.addHistory(entry));
    ipcMain.handle('history:clearHistory', () => historyManager.clearHistory());
    
    // LLM 服务
    ipcMain.handle('llm:testConnection', (e, modelKey) => llmService.testConnection(modelKey));
    ipcMain.handle('llm:sendMessage', (e, params) => llmService.sendMessage(params));
    
    // 提示词服务
    ipcMain.handle('prompt:optimize', (e, params) => promptService.optimize(params));
    ipcMain.handle('prompt:iterate', (e, params) => promptService.iterate(params));
    

阶段三:通信与前端改造

6. 重构预加载脚本

  • 文件: packages/desktop/preload.js
  • 删除内容: 所有 fetch 拦截和模拟逻辑
  • 新增内容: 结构化的 electronAPI 对象
  • 示例:
    javascript
    contextBridge.exposeInMainWorld('electronAPI', {
      models: {
        getAllModels: () => ipcRenderer.invoke('models:getAllModels'),
        saveModel: (model) => ipcRenderer.invoke('models:saveModel', model),
        // ...
      },
      templates: {
        getAllTemplates: () => ipcRenderer.invoke('templates:getAllTemplates'),
        // ...
      },
      // ...
    });
    

7. 创建渲染进程服务代理类

  • 目标: 为每个核心服务创建 Electron 代理类
  • 文件清单:
    • packages/core/src/services/model/electron-proxy.ts
    • packages/core/src/services/template/electron-proxy.ts
    • packages/core/src/services/history/electron-proxy.ts
    • packages/core/src/services/prompt/electron-proxy.ts
  • 要求: 每个代理类实现对应服务的接口,内部调用 window.electronAPI

8. 改造UI服务初始化逻辑

  • 文件: packages/ui/src/composables/useAppInitializer.ts
  • 逻辑: useAppInitializer 会自动检测运行环境。
    typescript
    if (isRunningInElectron()) { // Electron 环境
      // 初始化所有代理服务...
    } else { // Web 环境
      // 初始化所有真实服务...
    }
    

验证标准

功能验证

  • 桌面应用能够正常启动,无存储相关错误
  • 所有核心功能正常工作(模型管理、模板管理、历史记录等)
  • LLM 服务连接测试成功
  • 提示词优化和迭代功能正常

架构验证

  • 主进程和渲染进程职责清晰分离
  • IPC 通信基于稳定的高层接口
  • 不再有 AbortSignalHeaders 序列化问题
  • 代码结构清晰,易于维护和扩展

性能验证

  • 应用启动时间合理
  • IPC 通信延迟可接受
  • 内存使用稳定

风险控制

回滚策略

  • 保留当前 main.jspreload.js 的备份
  • 分阶段提交,确保每个阶段都可以独立回滚
  • 在完全验证新架构稳定性之前,保留旧的 IPC 处理器

测试策略

  • 每完成一个阶段,立即进行功能测试
  • 重点测试存储操作和 IPC 通信
  • 确保 Web 端功能不受影响

后续优化

第二阶段:文件持久化存储

  • MemoryStorageProvider 替换为基于文件的存储(如 electron-store
  • 实现数据迁移和备份功能

第三阶段:性能优化

  • 优化 IPC 通信频率
  • 实现增量数据同步
  • 添加缓存机制

状态: 📋 计划制定完成,等待执行 负责人: AI Assistant 预计完成时间: 分阶段执行,每阶段约1-2小时

实施进展

✅ 已完成项目

阶段一:核心改造 (core 包) - 100% 完成

  1. ✅ 创建 MemoryStorageProvider

    • 实现完整的 IStorageProvider 接口
    • 通过所有14个单元测试
    • 支持 Node.js 环境和测试环境
  2. ✅ 集成新的存储提供者

    • StorageFactory 中添加 'memory' 选项
    • 更新 core 包导出
  3. ✅ 创建工厂函数

    • createModelManager() 工厂函数
    • createTemplateManager() 工厂函数
    • createHistoryManager() 工厂函数
    • 所有工厂函数正确导出
  4. ✅ 接口完善与代理适配

    • ITemplateManager 接口中添加 isInitialized() 方法
    • ElectronTemplateManagerProxy 类中实现 isInitialized() 方法
    • 确保所有代理类正确实现了对应的接口

阶段二:后端改造 (主进程) - 100% 完成

  1. ✅ 重构 main.js

    • 使用 MemoryStorageProvider 替代 LocalStorageProvider
    • 实现完整的高层 IPC 服务接口
    • 支持 LLM、Model、Template、History 所有服务
  2. ✅ 更新 preload.js

    • 提供完整的 electronAPI 接口
    • 支持所有核心服务的 IPC 通信
    • 正确的错误处理和类型安全
  3. ✅ 创建代理类

    • ElectronLLMProxy 适配 IPC 接口
    • ElectronModelManagerProxy 实现模型管理
    • 更新全局类型定义

✅ 重大成果

桌面应用成功启动! 从最新的测试结果显示:

  1. ✅ 架构重构成功:从"底层 fetch 代理"成功迁移到"高层服务代理"
  2. ✅ 服务初始化正常:所有核心服务(ModelManager、TemplateManager、HistoryManager、LLMService)正常创建
  3. ✅ IPC 通信建立:高层服务接口正常工作
  4. ✅ UI 界面加载:Electron 窗口成功启动,前端界面正常显示
  5. ✅ 功能测试正常:可以进行 API 连接测试(失败是因为缺少 API 密钥,这是正常的)

🔧 待优化项目

  1. 存储统一性:部分模块仍在使用默认存储,需要确保全部使用 MemoryStorageProvider
  2. 错误处理优化:改进存储错误的中文显示
  3. 第二阶段存储:实现文件持久化存储(可选)

📊 架构对比

方面旧架构(底层 fetch 代理)新架构(高层服务代理)
稳定性❌ 脆弱,IPC 传输问题频发✅ 稳定,高层接口通信
可维护性❌ 复杂的 Response 模拟✅ 清晰的职责分离
存储兼容性❌ Node.js 环境不支持 localStorage✅ 专用的 MemoryStorageProvider
代码复用❌ 重复的代理逻辑✅ 主进程直接消费 core 包
类型安全❌ 复杂的类型适配✅ 完整的 TypeScript 支持

架构结论: 本次重构已圆满完成。随着统一初始化器 useAppInitializer 的引入和应用,桌面端的"高层服务代理"架构已完全落地,实现了各平台间架构的统一和代码的高度复用。

最后更新: 2024年12月29日