Electron 架构详解:Chromium + Node.js 如何协同工作
Electron 让你用 JavaScript、HTML、CSS 写桌面应用——VS Code、Discord、Slack 都是它做的。它不是什么黑科技,本质就是把 Chromium(浏览器内核)和 Node.js(服务端运行时)打包在一起,让 Web 页面能调用系统级 API。
三层架构
Electron 的架构可以拆成三层来看:
shell┌──────────────────────────────────────────────┐ │ 你的应用代码 │ ├──────────────────┬───────────────────────────┤ │ Chromium │ Node.js │ │ (渲染 UI) │ (系统 API、文件、网络) │ ├──────────────────┴───────────────────────────┤ │ 操作系统 (Windows / macOS / Linux) │ └──────────────────────────────────────────────┘
- Chromium:负责把 HTML/CSS/JS 渲染成用户看到的界面。Electron 内嵌了完整的 Chromium,所以你的应用就是一个独立的浏览器窗口
- Node.js:负责和操作系统打交道——读写文件、创建子进程、访问网络、操作剪贴板等。Electron 内嵌了完整的 Node.js 运行时
- 你的代码:运行在上述两个环境之上,通过 Electron 提供的 API 把两者串联起来
这就是 Electron 的核心卖点:一个代码库同时拥有浏览器的渲染能力和 Node.js 的系统能力,编译一次就能跑在 Windows、macOS、Linux 上。
多进程模型
Electron 继承了 Chromium 的多进程架构。这不是随意设计——Chromium 之所以用多进程,是因为单个网页崩溃不应该拖垮整个浏览器。Electron 同理:一个窗口崩了,其他窗口和主进程还能继续工作。
shell主进程 (Node.js) ├── 渲染进程 1 (Chromium) → 窗口 A ├── 渲染进程 2 (Chromium) → 窗口 B ├── 渲染进程 3 (Chromium) → 窗口 C └── GPU 进程 (共享)
主进程
- 应用入口,
package.json的main字段指向的文件 - 运行在 Node.js 环境中,可以使用
fs、path、child_process等所有 Node.js 模块 - 负责创建 BrowserWindow、管理应用生命周期(
app.whenReady()、app.quit()) - 处理原生对话框、系统菜单、托盘图标
渲染进程
- 每个 BrowserWindow 对应一个独立的渲染进程
- 运行在 Chromium 环境中,就是一个完整的网页运行环境
- 默认不能直接使用 Node.js API(安全原因),需要通过 preload 脚本桥接
GPU 进程
- Chromium 自动管理,负责图形渲染(硬件加速)
- 一般不需要手动干预,但如果 GPU 加速导致问题,可以通过
app.disableHardwareAcceleration()关闭
两个运行时怎么协作
Chromium 和 Node.js 各自有一套事件循环。Electron 在底层把它们整合到了一起:
- Node.js 的 libuv 事件循环 和 Chromium 的消息循环 被合并,两个环境的 I/O 和定时器可以互不阻塞地运行
- 你可以在同一个 JavaScript 上下文中既用
setTimeout(浏览器 API)又用fs.readFile(Node.js API)
但在渲染进程中,出于安全考虑,这种融合是被限制的——contextIsolation 默认开启,Node.js API 被隔离。你只能通过 preload 脚本和 IPC 通信来间接使用系统能力。
IPC 通信机制
主进程和渲染进程之间通过 IPC(进程间通信)传递消息:
javascript// 主进程 ipcMain.handle('read-config', async () => { const data = await fs.promises.readFile('config.json', 'utf-8') return JSON.parse(data) }) // 渲染进程(通过 preload 暴露的 API) const config = await window.electronAPI.readConfig()
通信是异步的,数据经过结构化克隆序列化——所以不能传函数、DOM 节点或循环引用的对象。
Electron 的优势和代价
优势
- 跨平台:一套代码跑三个系统,开发成本远低于分别写原生应用
- 前端友好:会写网页就能写桌面应用,团队不需要学 Swift / C# / Qt
- 生态丰富:npm 上所有包都能用,Web 社区的 UI 库(React、Vue)直接拿来用
- 自动更新:内置
autoUpdater,不需要自己实现增量更新
代价
- 包体积大:内嵌 Chromium + Node.js,最小打包也要 100MB+
- 内存占用高:每个渲染进程就是一个 Chromium 标签页,开多窗口内存涨得很快
- 性能不如原生:JS 的执行效率和内存管理比 C++/Rust 差,CPU 密集型任务会卡顿
- 启动慢:冷启动需要加载 Chromium 和 Node.js,比原生应用慢
这些代价不是"优化一下就好了"——它们是 Electron 架构的固有特征。如果你的应用对包体积、内存或启动速度有硬性要求(比如轻量工具类应用),Electron 可能不是最佳选择。Tauri(Rust + WebView)和 Wails(Go + WebView)是更轻量的替代方案。
什么时候该用 Electron
| 适合 | 不适合 |
|---|---|
| 内容型应用(编辑器、笔记、聊天) | 轻量工具(计算器、截图) |
| 需要丰富 UI 的桌面端 | 对启动速度极敏感 |
| 团队是前端为主 | 需要极低内存占用 |
| 需要快速跨平台上线 | 大量原生系统集成 |
Electron 最大的价值是降低桌面应用的开发门槛。如果团队已经会写 Web 应用,Electron 能让你们在几周内交付一个可用的桌面端——这个效率优势是原生开发无法比拟的。