4、Electron入门:从架构到第一个应用
Electron 这东西,说白了就是用前端技术写桌面应用。我最早接触它的时候,心里还犯嘀咕:一个浏览器壳子能有多靠谱?后来在项目中用它做了个 EDA 工具的辅助面板,才发现这玩意儿真香。今天咱们就把它掰开揉碎了讲清楚。
4.1 Electron 架构:主进程与渲染进程
Electron 的架构其实不复杂。它有两个核心角色:主进程和渲染进程。你可以把它们想象成一个公司里的老板和员工。
- 主进程:一个应用只有一个。它负责管理窗口、系统菜单、文件对话框这些底层操作。说白了,它就是那个发号施令的人。
- 渲染进程:每个窗口对应一个。它负责显示页面、处理用户交互。每个窗口就像一个小员工,各干各的活。
为什么会这样设计?我刚开始也觉得多此一举。后来在项目中遇到一个坑:如果所有逻辑都跑在渲染进程里,一旦页面卡死,整个应用就崩了。主进程和渲染进程分开,一个窗口挂了,其他窗口还能正常工作。嗯,这就是架构设计的智慧。
核心要点:主进程是 Node.js 环境,渲染进程是浏览器环境。两者不能直接访问对方的 API。
下面这张图是我自己画的,帮你理清它们的关系:
4.2 创建第一个 Electron 应用
光说不练假把式。咱们直接上手创建一个最简单的 Electron 应用。我习惯用 npm 初始化项目,这样依赖管理更清晰。
第一步,创建项目目录并初始化:
mkdir my-electron-app
cd my-electron-app
npm init -y
第二步,安装 Electron:
npm install electron --save-dev
第三步,创建主进程文件 main.js:
const { app, BrowserWindow } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
第四步,创建 index.html:
<!DOCTYPE html>
<html>
<head>
<title>我的第一个 Electron 应用</title>
</head>
<body>
<h1>Hello, Electron!</h1>
<p>这是一个桌面应用</p>
</body>
</html>
第五步,修改 package.json,添加启动脚本:
"scripts": {
"start": "electron ."
}
然后运行 npm start,就能看到你的第一个 Electron 应用了。
小提示:nodeIntegration: true 允许渲染进程使用 Node.js API。但在生产环境中,我建议你关闭它,用更安全的 IPC 方式通信。
4.3 进程间通信(IPC)基础
主进程和渲染进程怎么聊天?靠的就是 IPC(Inter-Process Communication)。Electron 提供了 ipcMain 和 ipcRenderer 两个模块。
我曾经在项目中犯过一个低级错误:直接在渲染进程里用 require('fs') 读写文件。结果安全策略一开,全崩了。后来老老实实用 IPC,反而更清晰。
来看一个最简单的 IPC 示例:
主进程(main.js):
const { ipcMain } = require('electron')
ipcMain.handle('get-user-data', async (event, userId) => {
// 模拟从数据库获取数据
return { id: userId, name: '张三', role: '工程师' }
})
渲染进程(renderer.js):
const { ipcRenderer } = require('electron')
async function loadUserData() {
const userData = await ipcRenderer.invoke('get-user-data', 123)
console.log(userData)
// 输出: { id: 123, name: '张三', role: '工程师' }
}
这个模式叫「请求-响应」。渲染进程发请求,主进程处理并返回结果。简单、安全、好用。
注意:不要在主进程里直接操作 DOM,也不要在渲染进程里调用系统 API。各司其职,才能避免踩坑。
除了 invoke/handle,还有 send/on 模式,适合单向消息推送。比如主进程通知渲染进程「文件下载完成」:
// 主进程
win.webContents.send('download-complete', { filePath: '/tmp/file.pdf' })
// 渲染进程
ipcRenderer.on('download-complete', (event, data) => {
alert(`文件已下载到:${data.filePath}`)
})
这两种模式基本覆盖了 90% 的通信场景。你想想看,是不是很简单?
4.4 避坑指南
最后分享几个我踩过的坑:
- contextIsolation 一定要理解清楚:默认是 true,这时候渲染进程不能直接访问 Node.js API。如果你非要开,记得评估安全风险。
- 开发时记得开 DevTools:
win.webContents.openDevTools()能帮你省掉很多调试时间。 - 打包前检查依赖:有些 npm 包在 Electron 里可能不兼容,尤其是那些依赖原生模块的。
我曾经在项目里因为忘了设置 webPreferences,导致 IPC 一直不通。查了半天才发现是 contextIsolation 默认开启,而我的代码没做适配。嗯,这种低级错误,犯一次就够了。
好了,Electron 的基础架构和 IPC 就讲到这里。记住:主进程管系统,渲染进程管界面,IPC 是它们之间的桥梁。这个思路捋顺了,后面学什么都会轻松很多。
公众号:蓝海资料掘金营,微信deep3321