docs/archives/115-ipc-serialization-fixes/proxy-layer-serialization.md
将IPC序列化处理从UI层移动到ElectronProxy层,实现统一的、对Vue组件透明的序列化处理机制。
虽然main.js中有safeSerialize处理,但错误发生在IPC传输阶段:
Vue组件 → ElectronProxy → preload.js → [IPC传输] → main.js
↑
错误发生在这里
文件: packages/core/src/utils/ipc-serialization.ts
/**
* 安全序列化函数,用于清理Vue响应式对象
*/
export function safeSerializeForIPC<T>(obj: T): T {
if (obj === null || obj === undefined) {
return obj;
}
if (typeof obj !== 'object') {
return obj;
}
try {
return JSON.parse(JSON.stringify(obj));
} catch (error) {
console.error('[IPC Serialization] Failed to serialize object:', error);
throw new Error(`Failed to serialize object for IPC: ${error instanceof Error ? error.message : String(error)}`);
}
}
// packages/core/src/services/template/electron-proxy.ts
import { safeSerializeForIPC } from '../../utils/ipc-serialization';
export class ElectronTemplateManagerProxy implements ITemplateManager {
async saveTemplate(template: Template): Promise<void> {
// 自动序列化,防止Vue响应式对象IPC传递错误
const safeTemplate = safeSerializeForIPC(template);
return this.electronAPI.createTemplate(safeTemplate);
}
}
// packages/core/src/services/model/electron-proxy.ts
export class ElectronModelManagerProxy implements IModelManager {
async addModel(key: string, config: ModelConfig): Promise<void> {
const safeConfig = safeSerializeForIPC({ ...config, key });
await this.electronAPI.model.addModel(safeConfig);
}
async updateModel(key: string, config: Partial<ModelConfig>): Promise<void> {
const safeConfig = safeSerializeForIPC(config);
await this.electronAPI.model.updateModel(key, safeConfig);
}
}
// packages/core/src/services/history/electron-proxy.ts
export class ElectronHistoryManagerProxy implements IHistoryManager {
async addRecord(record: PromptRecord): Promise<void> {
const safeRecord = safeSerializeForIPC(record);
return this.electronAPI.history.addRecord(safeRecord);
}
async createNewChain(record: Omit<PromptRecord, 'chainId' | 'version' | 'previousId'>): Promise<PromptRecordChain> {
const safeRecord = safeSerializeForIPC(record);
return this.electronAPI.history.createNewChain(safeRecord);
}
async addIteration(params: {...}): Promise<PromptRecordChain> {
const safeParams = safeSerializeForIPC(params);
return this.electronAPI.history.addIteration(safeParams);
}
}
// packages/core/src/services/prompt/electron-proxy.ts
export class ElectronPromptServiceProxy implements IPromptService {
async optimizePrompt(request: OptimizationRequest): Promise<string> {
const safeRequest = safeSerializeForIPC(request);
return this.api.optimizePrompt(safeRequest);
}
}
现在Vue组件可以直接调用服务,无需关心序列化:
// TemplateManager.vue - 修复前
import { createSafeTemplate } from '../utils/ipc-serialization'
const safeTemplate = createSafeTemplate(updatedTemplate)
await getTemplateManager.value.saveTemplate(safeTemplate)
// TemplateManager.vue - 修复后
await getTemplateManager.value.saveTemplate(updatedTemplate) // 自动序列化
Vue组件层 - 业务逻辑,无需关心IPC细节
↓
ElectronProxy层 - 自动序列化,IPC调用
↓
IPC传输层 - 纯净JavaScript对象传输
↓
Main进程层 - 双重保护(safeSerialize)
Vue组件 → ElectronProxy序列化 → IPC传输 → Main.js序列化 → 业务逻辑
↑ ↑
第一层保护 第二层保护
(必需,解决传输问题) (防御性,处理边缘情况)
packages/core/src/utils/ipc-serialization.ts - 统一序列化工具packages/core/src/services/template/electron-proxy.ts - 模板管理代理packages/core/src/services/model/electron-proxy.ts - 模型管理代理packages/core/src/services/history/electron-proxy.ts - 历史记录代理packages/core/src/services/prompt/electron-proxy.ts - 提示词服务代理packages/core/src/services/llm/electron-proxy.ts - LLM服务代理packages/core/src/services/preference/electron-proxy.ts - 偏好设置代理packages/core/src/index.ts - 导出序列化工具packages/ui/src/utils/ipc-serialization.ts - 删除UI层序列化工具packages/ui/src/components/TemplateManager.vue - 移除手动序列化packages/ui/src/components/ModelManager.vue - 移除手动序列化packages/ui/src/composables/usePromptOptimizer.ts - 移除手动序列化packages/ui/src/composables/usePromptHistory.ts - 移除手动序列化async newMethod(complexObject: SomeType): Promise<ResultType> {
// 总是序列化复杂对象参数
const safeObject = safeSerializeForIPC(complexObject);
return this.electronAPI.someService.newMethod(safeObject);
}
async simpleMethod(id: string, count: number): Promise<void> {
// 基本类型无需序列化
return this.electronAPI.someService.simpleMethod(id, count);
}
import { debugIPCSerializability } from '@prompt-optimizer/core';
// 开发时检查对象是否可序列化
debugIPCSerializability(complexObject, 'MyObject');
这次修复实现了:
通过这种方式,我们彻底解决了"An object could not be cloned"错误,同时建立了可持续的架构模式。