docs/archives/115-ipc-serialization-fixes/architecture-evolution.md
本文档记录了Electron IPC序列化处理从UI层手动处理到ElectronProxy层自动处理的架构演进过程。
问题:Vue响应式对象无法通过Electron IPC传递
TemplateManager.vue:1068 保存提示词失败: Error: An object could not be cloned.
ModelManager.vue:1023 添加模型失败: Error: An object could not be cloned.
解决方案:在UI层手动序列化
// UI层手动序列化
import { createSafeModelConfig } from '../utils/ipc-serialization'
const config = createSafeModelConfig(formData.value)
await modelManager.addModel(key, config)
问题:
改进思路:将序列化处理移到ElectronProxy层
新架构:
Vue组件 → ElectronProxy自动序列化 → IPC → Main.js序列化
↑ 透明使用 ↑ 安全传输 ↑ 双重保护
实现方案:
最终效果:
// Vue组件中直接使用,无需关心序列化
await modelManager.addModel(key, {
llmParams: formData.value.llmParams // 自动序列化
})
┌─────────────┐ 手动序列化 ┌──────────────┐ IPC ┌─────────────┐
│ Vue组件 │ ──────────────→ │ ElectronProxy│ ────────→ │ Main进程 │
│ (需要手动) │ │ (透传) │ │ (双重保护) │
└─────────────┘ └──────────────┘ └─────────────┘
问题:
┌─────────────┐ 直接传递 ┌──────────────┐ IPC ┌─────────────┐
│ Vue组件 │ ──────────────→ │ ElectronProxy│ ────────→ │ Main进程 │
│ (透明使用) │ │ (自动序列化) │ │ (双重保护) │
└─────────────┘ └──────────────┘ └─────────────┘
优势:
packages/ui/src/utils/ipc-serialization.ts - UI层序列化工具packages/core/src/utils/ipc-serialization.ts - 新增统一序列化工具packages/core/src/services/*/electron-proxy.ts - 6个代理类自动序列化packages/ui/src/components/ModelManager.vue - 移除手动序列化packages/ui/src/composables/usePromptOptimizer.ts - 移除手动序列化packages/ui/src/composables/usePromptHistory.ts - 移除手动序列化// 修改前:需要手动序列化
import { createSafeModelConfig } from '../utils/ipc-serialization'
const config = createSafeModelConfig({
name: newModel.value.name,
llmParams: newModel.value.llmParams
})
await modelManager.addModel(key, config)
// 修改后:直接使用
const config = {
name: newModel.value.name,
llmParams: newModel.value.llmParams
}
await modelManager.addModel(key, config) // 自动序列化
这次架构演进是一个很好的例子,展示了如何通过合理的架构设计来解决技术问题,同时提升开发体验。
在解决Vue组件类型错误时,发现了一个重要的架构问题:ElectronProxy层承担了过多的数据格式转换职责。
现象:
[object Object]错误global.d.ts中定义fetchModelList返回string[],但实际返回ModelOption[]Web版 vs 桌面版的关键差异:
修复类型定义:
// 修复前
fetchModelList: (provider: string, customConfig?: any) => Promise<string[]>;
// 修复后
fetchModelList: (provider: string, customConfig?: any) => Promise<Array<{value: string, label: string}>>;
简化代理层:
// ElectronProxy只负责IPC通信,不做数据转换
async fetchModelList(provider: string, customConfig?: Partial<any>): Promise<ModelOption[]> {
const safeCustomConfig = customConfig ? safeSerializeForIPC(customConfig) : customConfig;
return this.electronAPI.llm.fetchModelList(provider, safeCustomConfig);
}
移除冗余事件:删除不必要的@select事件处理,简化数据流
这次经验强化了我们对IPC架构设计的理解,为未来的跨进程功能开发提供了重要指导。