Chatbox架构深度剖析:Electron主进程、Preload桥接与本地数据存储是怎么实现的
【免费下载链接】chatboxPowerful AI Client项目地址: https://gitcode.com/GitHub_Trending/ch/chatbox
Chatbox 是一款跨平台的 AI 对话客户端,支持 OpenAI、Claude、Ollama、SiliconFlow 等多家模型服务商。本文带你深入 Chatbox 架构,用最少代码、最多的思路,讲清楚 Electron 主进程、Preload 脚本与本地数据存储三者是如何协同工作的——即使你是新手,也能快速看懂这个桌面应用的完整骨架。
一、先看全貌:三大进程分工
Chatbox 基于Electron + React + TypeScript构建(依赖清单见 package.json),整体遵循 Electron 的标准三层架构:
| 层 | 位置 | 职责 |
|---|---|---|
| 主进程(Main) | src/main/ | 创建窗口、管理配置、系统级能力(代理、自动更新、日志) |
| 预加载(Preload) | src/main/preload.ts | 用contextBridge安全地把 IPC 能力"打包"给页面 |
| 渲染进程(Renderer) | src/renderer/ | React 界面、会话管理、Jotai 状态、本地数据读写 |
入口在 src/main/main.ts:app.whenReady()后调用createWindow()创建BrowserWindow,并启动代理初始化proxy.init()。
二、主进程:不只是"开个窗口"
打开 src/main/main.ts,主进程干了几件关键的事:
创建窗口并挂载 Preload
创建
BrowserWindow时通过webPreferences.preload指定 preload 脚本路径(main.ts#L91-L104)。注意区分开发态与打包态:开发时指向.erb/dll/preload.js,生产时指向preload.js。一份"IPC 服务清单"
主进程用大量
ipcMain.handle注册了渲染进程可调用的能力,相当于一个本地"API 表":- 数据存取:
getStoreValue/setStoreValue/delStoreValue/getAllStoreValues(main.ts#L178-L194) - 系统信息:
getVersion、getPlatform、getLocale、getHostname - 系统能力:
openLink(外部浏览器打开链接)、relaunch(重启应用)、shouldUseDarkColors(跟随系统深色模式) - 配置相关:
getConfig、getSettings、ensureProxy(全局代理设置)
- 数据存取:
自动更新
AppUpdater类使用electron-updater从官方源检查新版本,下载完成后弹窗询问是否重启安装(main.ts#L29-L51)。全局代理
src/main/proxy.ts 通过
session.defaultSession.setProxy为整个应用配置代理,让 AI 请求可以走代理网络——这也是 Chatbox 能在各种网络环境下稳定连接 OpenAI 的关键。
三、Preload:一道安全"隔离墙"
很多新手会问:为什么不直接让页面调用ipcRenderer?答案在 src/main/preload.ts:
const electronHandler: ElectronIPC = { invoke: ipcRenderer.invoke, onSystemThemeChange: (callback) => { ipcRenderer.on('system-theme-updated', callback) return () => ipcRenderer.off('system-theme-updated', callback) }, } contextBridge.exposeInMainWorld('electronAPI', electronHandler)它做了两件事:
- 收窄接口:只暴露
invoke和两个主题/窗口事件订阅,页面拿不到完整的ipcRenderer,无法任意调用系统能力; - 统一命名:通过
contextBridge.exposeInMainWorld('electronAPI', ...),渲染进程里就能直接用window.electronAPI。
接口契约定义在 src/shared/electron-types.ts,主进程、Preload、渲染进程三方共享同一份类型,保证通道名不写错。
四、本地数据存储:electron-store 的三层封装
Chatbox 的会话、配置、Copilot 数据都离线保存在本机,没有强制登录。这条存储链由上而下分三层:
第 1 层:主进程磁盘层
src/main/store-node.ts 使用electron-store(JSON 文件存储),定义了settings、configs等类型化字段,并处理"首次启动时写入默认配置"的逻辑。store.path会打印存储文件位置——它就在用户的应用数据目录下。
第 2 层:渲染进程抽象层
src/renderer/storage/BaseStorage.ts 提供setItem / getItem / removeItem / getAll / setAll的异步接口,内部全部走 IPC 调到主进程。子类 src/renderer/storage/StoreStorage.ts 定义了业务存储键:
| 存储键 | 内容 |
|---|---|
chat-sessions | 所有聊天会话与消息 |
configs | 各 AI 服务商的 Key、模型配置 |
settings | 显示、聊天等行为设置 |
myCopilots | 用户自定义 Copilot |
它还有一个贴心细节:首次取不到chat-sessions时,会按系统语言自动注入中文或英文的默认示例会话(StoreStorage.ts#L18-L35),这就是你刚装好 Chatbox 就看到的欢迎对话。
第 3 层:平台适配层
src/renderer/packages/platform.ts 把window.electronAPI包装成DesktopPlatform,对上层提供getStoreValue、getConfig、ensureProxyConfig等语义化方法。渲染组件(如设置面板、会话列表)都只依赖这一层,未来若换平台(比如浏览器版)只需替换实现。
五、三层如何配合:一条数据的一生
以"保存一条新消息"为例,完整链路是:
- React 组件调用 Jotai 的 session 动作(
src/renderer/stores/),修改内存中的会话状态; - 动作层调用
platform.setStoreValue('chat-sessions', ...); DesktopPlatform序列化为 JSON,经window.electronAPI.invoke('setStoreValue', ...)发出 IPC;- Preload 把它转发给主进程,
ipcMain.handle('setStoreValue')接到请求; - 主进程
store.set(key, data)把数据写进本地 JSON 文件,下次启动自动恢复。
整个过程渲染进程从不直接碰磁盘,所有落盘操作都由主进程统一完成——这正是 Electron 应用保证数据一致性和安全性的标准做法。
六、总结:这套架构值得你抄作业吗?
Chatbox 的架构并没有炫技,而是把 Electron 最佳实践落地得相当干净:
- ✅ 主进程集中管理窗口、更新、代理、日志等系统能力;
- ✅ Preload 用
contextBridge最小化暴露 IPC,兼顾安全与灵活; - ✅ 存储走
electron-store+ 三层封装,业务代码完全不感知平台差异; - ✅
src/shared/目录放置共享类型(见 src/shared/types.ts),跨进程类型安全。
如果你想动手学习,建议阅读顺序:src/main/main.ts → src/main/preload.ts → src/renderer/packages/platform.ts → src/renderer/storage/。顺着"一条消息"的链路读下来,一个完整的桌面 AI 客户端架构就清晰了。🚀
【免费下载链接】chatboxPowerful AI Client项目地址: https://gitcode.com/GitHub_Trending/ch/chatbox
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考