Electron 桌面开发 - 笔记 📒
Siona
传统桌面端应用开发
- 原生开发
- 直接将语言编译成可执行文件
- 直接调用系统 API,完成 UI 绘制
- 运行效率高
- 对技术要求高,导致开发速度慢
- 例如:开发 Windows 应用,需要使用 C++、MFC、QT 等;开发 MacOs 应用,需要使用 Swift 语言
- 托管平台
- 一次编译后,得到中间文件,通过平台或者虚拟机完成二次加载编译或解释运行
- C#、.Net、Framework 开发 Windows 应用
- Java、Swing
Electron 桌面开发
Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到二进制的 Electron 允许您保持一个 JavaScript 代码代码库 并创建在 Windows 上运行的跨平台应用 macOS 和 Linux —— 不需要本地开发经验。
- GitHub 开源的框架
- 构建扩平台桌面应用程序
- 最初是和 Atom 编辑器 于 2014 开源
- 使用 Electron 开发的应用:postman、语雀等
- 适用场景
- 特定的领域软件(POS 机、财务软件、开发者工具、打印场景等,用到系统能力)
- 同时开发 Web + 桌面应用
Electron 核心技术


Electron 等于
- chromium(Chrome 实验版)
- NodeJS(操作系统底层 API 能力 —— path、fs)
- Native API(调用原生应用程序接口)
Electron 优势
- 兼容性:可以使用最新的 API 和语法;不需要考虑浏览器的样式和代码兼容性
- NodeJS:使用 npm 模块,可直接调用系统 API 操作文件
- 跨域:使用 request 模块发起网络请求
Electron 劣势
- 应用体积过大:使用 NodeJS 开发、electron-builder 打包等导致应用体积较大
- 支持度:某些功能受限(例如,无法获取系统文件中选中的文件状态,必须调用相应接口才能实现)
- 性能:CPU 密集型应用性能较差
Electron 基本原理


可参考文章:
Electron 生命周期

Electron + Vite + Vue 实战
Electron 依赖安装
npm install electron --save-dev
npm install electron-builder --save-dev
npm install @electron/remote --save-dev
npm 安装 Electron 报错

报错原因:镜像问题
- npm 的镜像,不要使用淘宝镜像;
- electron 的镜像,官方文档未提及 🥲
# ① 打开 npm 的配置文件
npm config edit
# ② 配置镜像
registry=https://registry.npmmirror.com
electron_mirror=https://cdn.npmmirror.com/binaries/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
# ③ 关闭该窗口,重启命令行,删除 node_modules 文件夹,并执行下面命令清除缓存,再重新安装依赖
npm cache clean --force
# OK 啦~
siona@Sionas-MacBook-Pro electron-study % npm install electron --save-dev
added 120 packages in 21s

📢 或者,不修改 npm 配置文件,而是在项目中创建 .npmrc
文件进行设置 electron 镜像地址。
Electron 启动报错

/Users/siona/.nvm/versions/node/v20.10.0/bin/npm run start
> electron-study@0.0.0 start
> electron .
2024-03-24 17:36:15.481 Electron[17602:951417] WARNING: Secure coding is automatically enabled for restorable state! However, not on all supported macOS versions of this application. Opt-in to secure coding explicitly by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState:.
解决方法:
# 报错
ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/Users/siona/Documents/WorkSpaces/WebstormProjects/electron-study/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
# 解决方法:去掉 package.json 中的参数 "type": "module" 即可。
Electron 启动成功效果
图中效果是由于设置了 win.webContents.openDevTools();
开启控制台(便于调试)。
nodemon
监控 js 文件变更,不需要修改 main.js 等文件之后,重新启动项目。

// ① 创建 nodemon.json 文件
// 简单使用:监控 js 文件变化
{
"options": {
"extensions": ["js"]
}
}
// ② 修改 package.json 启动脚本
"scripts": {
"start": "nodemon --exec electron .",
}
# 控制台:nodemon 实际效果,修改了 main.js 中 electron browser window 的 width
> electron-study@0.0.0 start
> nodemon --exec electron .
[nodemon] 3.1.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `electron .`
[nodemon] restarting due to changes...
[nodemon] starting `electron .`
preload 预加载
主进程可以通过 NodeJS 访问系统 API,但是不能读取 DOM。
- preload 能够在渲染器进程加载之前加载,并且能够有权访问两个渲染器全局(window、document)node 环境。
// ① 创建 preload.js 文件
// ② 在 main.js 主进程中引入 preload.js 文件
// 此处,只贴出关键代码,请注意!
const path = require("path");
win = new BrowserWindow({
width: 900,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
}
});
小 demo
界面中显示 node 版本、chromium 版本、electron 版本。
// index.html
<body>
chrome 版本:<span id="chrome-version"></span><br/>
node 版本:<span id="node-version"></span><br/>
electron 版本:<span id="electron-version"></span>
<script src="./renderer.js"></script>
</body>
// main.js 主进程
const {app, BrowserWindow} = require("electron");
const path = require("path");
let win;
const createWindow = () => {
win = new BrowserWindow({
width: 800,
heigth: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js');
},
});
win.loadFile('index.html');
win.webContents.openDevTools(); // 开启控制台,便于调试
// 导航完成时触发
win.webContents.on('did-finish-load', () => {
win.webContents.send('msg', '消息来自主进程');
});
};
app.whenReady().then(createWindow);
// preload.js 预加载文件
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector);
if (element) {
element.innerText = text;
}
};
console.log('versions', process.versions);
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency]);
}
});
效果图:

进程间通信
主进程(main.js)主动向渲染进程(renderer.js)发送消息 win.webContents.send()
// main.js 主进程
const {app, BrowserWindow} = require("electron");
const path = require("path");
let win;
const createWindow = () => {
win = new BrowserWindow({
width: 800,
heigth: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
// 配置 node 能力
nodeIntegration: true,
contextIsolation: false,
},
});
win.loadFile('index.html');
win.webContents.openDevTools(); // 开启控制台,便于调试
// 导航完成时触发
win.webContents.on('did-finish-load', () => {
win.webContents.send('msg', '消息来自主进程');
});
};
app.whenReady().then(createWindow);
// renderer.js 渲染进程
// 通过 ipcRenderer 来监听消息
const {ipcRenderer} = require("electron");
ipcRenderer.on('msg', (event, message) => {
alert(message);
});
渲染进程主动向主进程发送消息
扩展
Electron 不支持 Windows XP,NW 支持。