一、前言
在使用 Electron 开发桌面应用时,经常会接触到:
- Main Process(主进程)
- Renderer Process(渲染进程)
- Preload Script(预加载脚本)
- IPC(Inter-Process Communication,进程间通信)
很多刚开始学习 Electron 的开发者容易把它们理解成普通的前端线程,但实际上 Electron 的核心架构是多进程模型。
例如我们正在开发一个 Electron + Vue 桌面应用:
Electron
│
├── Main Process
│ │
│ ├── 创建窗口
│ ├── 文件系统
│ ├── SQLite
│ ├── Node.js
│ └── 系统级能力
│
├── Preload Script
│ │
│ └── 安全暴露 API
│
└── Renderer Process
│
├── Vue
├── HTML
├── CSS
└── 页面交互
那么,Vue 页面如果需要访问 SQLite、读取文件或者启动 Python 服务,就不能直接操作,而是需要通过 IPC 与主进程进行通信。
本文就详细介绍 Electron 的进程模型以及 IPC 通信方式。
二、Electron 的进程模型
Electron 主要由以下几个部分组成:
| 主进程(Main Process) | 创建和管理窗口、执行系统级操作、访问 Node.js API | app、BrowserWindow、ipcMain、globalShortcut |
| 渲染进程(Renderer Process) | 负责页面 UI 渲染和用户交互 | DOM、Vue、浏览器 API |
| 预加载脚本(Preload Script) | 连接主进程和渲染进程,在安全环境下暴露 API | contextBridge、ipcRenderer |
需要特别注意:
Preload 是一个脚本,而不是独立的 Electron 进程。
因此,更准确的理解应该是:
┌────────────────────────────────────────────┐
│ Electron Application │
│ │
│ ┌──────────────┐ │
│ │ Main Process │ │
│ │ │ │
│ │ Node.js │ │
│ │ SQLite │ │
│ │ File System │ │
│ └──────┬───────┘ │
│ │ IPC │
│ │ │
│ ┌──────▼────────┐ │
│ │ Preload │ │
│ │ contextBridge │ │
│ └──────┬────────┘ │
│ │ │
│ ┌──────▼──────────────┐ │
│ │ Renderer Process │ │
│ │ │ │
│ │ Vue │ │
│ │ HTML / CSS / DOM │ │
│ └─────────────────────┘ │
└────────────────────────────────────────────┘
三、主进程(Main Process)
主进程是 Electron 应用的核心进程。
通常一个 Electron 应用只有一个主进程。
主进程主要负责:
- 创建 BrowserWindow
- 管理应用生命周期
- 访问 Node.js API
- 操作文件系统
- 操作 SQLite
- 启动和管理 Python 服务
- 创建系统托盘
- 注册全局快捷键
- 处理 IPC
- 管理应用级状态
例如:
import { app, BrowserWindow } from 'electron'
let mainWindow: BrowserWindow | null = null
function createWindow() {
mainWindow = new BrowserWindow({
width: 1400,
height: 900,
webPreferences: {
preload: '/path/to/preload.js'
}
})
}
app.whenReady().then(() => {
createWindow()
})
主进程可以访问 Node.js:
import fs from 'node:fs'
import path from 'node:path'
因此,类似下面这些操作通常应该放在主进程:
读取文件
↓
SQLite
↓
启动 Python
↓
操作系统 API
↓
创建窗口
四、渲染进程(Renderer Process)
渲染进程主要负责 UI。
如果我们使用:
Electron + Vue 3 + TypeScript
那么 Vue 应用基本就是运行在渲染进程中。
例如:
<script setup lang="ts">
const handleClick = () => {
console.log('点击按钮')
}
</script>
<template>
<button @click="handleClick">
保存文章
</button>
</template>
渲染进程可以使用:
- Vue
- HTML
- CSS
- DOM
- window
- localStorage
- 浏览器 API
但是在安全配置下,不应该直接使用 Node.js API。
例如不建议在 Vue 页面中直接:
import fs from 'fs'
也不要让页面直接拥有完整的 Node.js 能力。
原因很简单:
如果网页代码可以直接访问 Node.js,那么一旦页面存在 XSS 等安全问题,攻击者可能获得文件系统等更高权限。
因此 Electron 提供了 Preload Script。
五、Preload Script
Preload 可以理解为:
渲染进程与主进程之间的安全桥梁。
Preload 通常运行在页面加载之前,并通过 contextBridge 向 Vue 暴露有限的 API。
例如:
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
getAppInfo: () => {
return ipcRenderer.invoke('app:getInfo')
}
})
这样 Vue 页面就可以使用:
window.electronAPI.getAppInfo()
但是 Vue 并没有直接获得:
ipcRenderer
或者:
fs
这样的底层能力。
整个调用关系:
Vue
│
│ window.electronAPI.getAppInfo()
↓
Preload
│
│ ipcRenderer.invoke()
↓
Main Process
│
│ ipcMain.handle()
↓
执行具体业务
六、什么是 IPC?
IPC 全称:
Inter-Process Communication
也就是:
进程间通信。
因为 Electron 的主进程和渲染进程是不同的进程,所以它们不能像普通 JavaScript 函数一样直接调用。
例如:
Vue
↓
我要读取一个 Markdown 文件
↓
Main Process
↓
fs.readFile()
↓
返回 Markdown 内容
↓
Vue
中间就需要通过 IPC 传递消息。
七、Electron 常见 IPC 通信方式
Electron 中最常见的 IPC 通信方式主要有:
| 请求-响应 | ipcRenderer.invoke() | ipcMain.handle() | 推荐 |
| 单向消息 | ipcRenderer.send() | ipcMain.on() | 无返回值 |
| 主进程主动推送 | ipcRenderer.on() | webContents.send() | 主进程主动通知 |
八、渲染进程 → 主进程:invoke / handle
这是开发桌面应用时最推荐的一种方式。
例如:
Vue
↓
invoke()
↓
Preload
↓
ipcRenderer.invoke()
↓
Main
↓
ipcMain.handle()
↓
返回结果
8.1 Main Process
import { ipcMain } from 'electron'
ipcMain.handle('app:getInfo', async () => {
return {
name: 'CSDN Auto',
version: '1.0.0'
}
})
8.2 Preload
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
getAppInfo: () => {
return ipcRenderer.invoke('app:getInfo')
}
})
8.3 Vue
const appInfo = await window.electronAPI.getAppInfo()
console.log(appInfo)
最终得到:
{
"name": "CSDN Auto",
"version": "1.0.0"
}
这种方式特别适合:
获取文章
保存文章
删除文章
查询 SQLite
创建任务
获取账号
读取配置
因为它具有明确的:
请求
↓
处理
↓
返回
关系。
九、渲染进程 → 主进程:send / on
如果不需要返回结果,可以使用:
ipcRenderer.send()
配合:
ipcMain.on()
例如:
Preload
contextBridge.exposeInMainWorld('electronAPI', {
writeLog: (message: string) => {
ipcRenderer.send('log:write', message)
}
})
Main
ipcMain.on('log:write', (_event, message) => {
console.log('[Renderer]', message)
})
Vue
window.electronAPI.writeLog('用户点击了发布按钮')
这种方式适合:
日志
埋点
通知
不需要返回值的操作
不过对于大多数业务请求,还是更推荐:
invoke / handle
十、主进程 → 渲染进程
有些时候不是 Vue 主动请求,而是主进程产生了新的状态,需要主动通知 Vue。
例如:
Python 自动发布文章
↓
任务进度发生变化
↓
Electron Main
↓
通知 Vue
↓
进度条更新
这时候可以使用:
webContents.send()
配合:
ipcRenderer.on()
10.1 Main Process
mainWindow.webContents.send(
'task:progress',
{
taskId: 'task_001',
progress: 60
}
)
10.2 Preload
contextBridge.exposeInMainWorld('electronAPI', {
onTaskProgress: (callback) => {
ipcRenderer.on('task:progress', (_event, data) => {
callback(data)
})
}
})
10.3 Vue
window.electronAPI.onTaskProgress((data) => {
console.log('任务进度:', data.progress)
})
页面就可以实时更新:
正在发布文章…
████████████░░░░░░░░ 60%
十一、推荐的 IPC 使用原则
实际开发中,可以按照下面的原则设计。
例如:
查询文章
保存文章
删除文章
创建任务
查询账号
读取配置
统一:
ipcRenderer.invoke()
↓
ipcMain.handle()
例如:
任务进度
Python 状态
发布日志
下载进度
窗口状态
使用:
webContents.send()
↓
ipcRenderer.on()
例如:
记录日志
发送统计信息
通知主进程刷新
不要所有东西都使用:
send / on
否则后期很容易出现:
发送了消息
但是不知道什么时候结束
也不知道有没有执行成功
业务代码会越来越难维护。
十二、推荐封装 IPC
随着项目越来越大,不建议把:
ipcMain.handle(…)
全部写在:
main.ts
里面。
例如:
electron/
├── ipc/
│ ├── app.ipc.ts
│ ├── window.ipc.ts
│ ├── article.ipc.ts
│ ├── task.ipc.ts
│ ├── account.ipc.ts
│ └── system.ipc.ts
│
├── services/
│ ├── article.service.ts
│ ├── task.service.ts
│ └── account.service.ts
│
└── main.ts
这样:
main.ts
│
├── 注册 app IPC
├── 注册 article IPC
├── 注册 task IPC
└── 注册 account IPC
十四、最终推荐的通信架构
对于一个中大型 Electron 项目,我比较推荐:
Vue Renderer
│
│
window.api
│
↓
Preload
│
│ IPC
↓
Electron Main
│ │
│ │
SQLite WebSocket
│ │
│ ↓
│ Python Engine
│ │
│ Playwright
│ │
│ ↓
│ CSDN
│
↓
本地数据
其中每一层只负责自己的事情:
| Vue | RendererUI、交互、页面状态 |
| Preload | 安全暴露 API |
| Electron Main | 系统能力、数据库、进程管理 |
| Python Engine | 浏览器自动化、CSDN 操作 |
| SQLite | 本地业务数据 |
| WebSocket | Electron 与 Python 双向通信 |
十六、总结
Electron 的核心并不是简单地把一个网页套进桌面窗口,而是一个基于多进程架构的桌面应用框架。
开发 Electron 应用时,可以简单记住:
Renderer
负责 UI
Preload
负责安全桥接
Main
负责系统能力
IPC
负责 Renderer ↔ Main 通信
WebSocket
负责 Electron ↔ Python Engine 通信
业务请求优先使用:
ipcRenderer.invoke()
↓
ipcMain.handle()
主进程主动推送状态使用:
webContents.send()
↓
ipcRenderer.on()
而对于 CSDN Auto 这样的桌面自动化软件,可以进一步采用:
Vue
↓
Preload
↓
IPC
↓
Electron Main
↓
WebSocket
↓
Python Engine
↓
Playwright
↓
CSDN
这种架构能够很好地将 UI、桌面能力、数据存储以及自动化能力 分离开来,也方便后续继续扩展 AI 写作、定时发布、多账号管理、任务队列等功能。
网硕互联帮助中心





评论前必须登录!
注册