Electron 详细教程
Electron 是一个使用 JavaScript, HTML 和 CSS 构建跨平台桌面应用程序的框架。它结合了 Chromium 渲染引擎和 Node.js 运行时,让你可以使用 web 技术开发原生桌面应用。
目录
- Electron 简介
- 环境准备
- 创建第一个 Electron 应用
- 项目结构
- 主进程与渲染进程
- 进程间通信
- 原生 API 使用
- 打包与分发
- 安全最佳实践
- 调试与性能优化
- 高级特性
Electron 简介
Electron 的主要特点:
- 跨平台:支持 Windows、macOS 和 Linux
- Web 技术:使用 HTML、CSS 和 JavaScript 构建界面
- Node.js 集成:可以访问文件系统等操作系统功能
- 丰富的 API:提供原生菜单、通知、对话框等
- 自动更新:内置自动更新支持
- 社区生态:有大量现成的模块和工具
知名 Electron 应用:VS Code、Slack、Discord、Figma、Twitch 等
环境准备
在开始之前,确保你的系统安装了:
- Node.js 12.x 或更高版本
- npm 或 yarn
- 适合你平台的构建工具(如 Windows 需要 Visual Studio Build Tools)
创建第一个 Electron 应用
- 创建项目文件夹并初始化:
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
}
})
// 加载 index.html
win.loadFile('index.html')
// 打开开发者工具
win.webContents.openDevTools()
}
// Electron 初始化完成后调用
app.whenReady().then(createWindow)
// 所有窗口关闭时退出应用 (macOS 除外)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// macOS 点击 Dock 图标时重新创建窗口
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
- 创建
index.html
文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello Electron!</title>
</head>
<body>
<h1>Hello Electron!</h1>
<p>Welcome to your Electron application.</p>
</body>
</html>
运行 HTML
- 修改
package.json
,添加启动脚本:
{
"name": "my-electron-app",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"devDependencies": {
"electron": "^latest"
}
}
- 启动应用:
npm start
项目结构
一个典型的 Electron 项目结构:
my-electron-app/
├── node_modules/ # 依赖项
├── main.js # 主进程脚本
├── preload.js # 预加载脚本
├── index.html # 主页面
├── renderer.js # 渲染进程脚本
├── styles.css # 样式表
├── package.json
└── package-lock.json
主进程与渲染进程
Electron 应用基于多进程架构:
- 主进程:运行
main.js
的进程,负责创建和管理应用窗口,可以访问所有 Electron API - 渲染进程:每个窗口运行一个独立的渲染进程,显示网页内容,默认情况下不能直接访问 Node.js API
主进程职责
- 创建和管理应用窗口
- 使用 Electron 的 API 创建原生应用菜单、对话框等
- 管理应用生命周期
- 实现自动更新
- 与操作系统交互
渲染进程职责
- 使用 HTML、CSS 和 JavaScript 渲染界面
- 响应用户交互
- 通过 IPC 与主进程通信来访问系统功能
进程间通信
Electron 提供了 ipcMain
和 ipcRenderer
模块来实现主进程和渲染进程间的通信。
基本 IPC 通信
- 在
main.js
中设置接收器:
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // 打印 "ping"
event.reply('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // 打印 "ping"
event.returnValue = 'pong'
})
- 在渲染进程 (HTML 文件中) 中发送消息:
<script>
const { ipcRenderer } = require('electron')
// 异步消息
ipcRenderer.send('asynchronous-message', 'ping')
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // 打印 "pong"
})
// 同步消息
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // 打印 "pong"
</script>
运行 HTML
使用预加载脚本安全地暴露 API
为了安全考虑,现代 Electron 版本默认禁用了渲染进程直接访问 Node.js API。推荐使用预加载脚本暴露特定功能:
- 创建
preload.js
:
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
sendMessage: (message) => ipcRenderer.send('message', message),
onReply: (callback) => ipcRenderer.on('reply', callback)
})
- 修改
main.js
中的 BrowserWindow 配置:
new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
- 在渲染进程中通过暴露的 API 通信:
window.electronAPI.sendMessage('hello')
window.electronAPI.onReply((event, arg) => {
console.log(arg)
})
原生 API 使用
创建原生菜单
const { Menu } = require('electron')
const template = [
{
label: 'File',
submenu: [
{
label: 'Open',
click: () => { console.log('Open clicked') }
},
{ type: 'separator' },
{ role: 'quit' }
]
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' }
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
显示原生对话框
const { dialog } = require('electron')
// 显示打开文件对话框
dialog.showOpenDialog({
properties: ['openFile', 'multiSelections']
}).then(result => {
console.log(result.filePaths)
}).catch(err => {
console.log(err)
})
// 显示消息对话框
dialog.showMessageBox({
type: 'info',
title: 'Information',
message: 'This is an information dialog',
buttons: ['OK', 'Cancel']
}).then(result => {
console.log(result.response)
})
系统通知
const { Notification } = require('electron')
new Notification({
title: 'Notification',
body: 'This is a notification'
}).show()
访问文件系统
const fs = require('fs')
// 读取文件
fs.readFile('path/to/file', 'utf-8', (err, data) => {
if (err) throw err
console.log(data)
})
// 写入文件
fs.writeFile('path/to/file', 'Hello Electron!', (err) => {
if (err) throw err
console.log('File saved!')
})
打包与分发
使用 electron-builder 打包
- 安装 electron-builder:
npm install electron-builder --save-dev
- 在
package.json
中添加配置:
{
"build": {
"appId": "com.example.myapp",
"win": {
"target": "nsis"
},
"mac": {
"category": "public.app-category.developer-tools"
},
"linux": {
"target": ["AppImage", "deb"]
}
},
"scripts": {
"pack": "electron-builder --dir",
"dist": "electron-builder"
}
}
- 运行打包命令:
npm run dist
打包完成后,安装包会生成在 dist
目录中。
打包配置选项
- target:指定打包格式 (nsis, zip, dmg, AppImage 等)
- icon:应用图标
- extraResources:包含额外资源文件
- asar:是否将应用打包为 asar 归档
- publish:自动更新配置
安全最佳实践
- 启用上下文隔离:防止渲染进程直接访问 Node.js API
- 使用预加载脚本:仅暴露必要的 API
- 禁用 Node.js 集成:对于不需要 Node.js 功能的渲染进程
- 验证 IPC 消息:不信任渲染进程发送的消息
- 使用 CSP:内容安全策略限制加载的资源
- 更新依赖:保持 Electron 和所有依赖项更新
示例安全配置:
new BrowserWindow({
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, 'preload.js')
}
})
调试与性能优化
调试主进程
- 使用 VSCode 调试配置:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": ["."],
"outputCapture": "std"
}
]
}
- 使用 Chrome 开发者工具:
mainWindow.webContents.openDevTools()
性能优化建议
- 减少 DOM 复杂度:简化页面结构
- 使用懒加载:延迟加载非关键资源
- 优化图像:压缩和适当缩放图像
- 避免同步操作:特别是在主进程中
- 使用 Web Workers:处理 CPU 密集型任务
- 分析性能:使用 Chrome 开发者工具的性能面板
高级特性
自动更新
- 安装 electron-updater:
npm install electron-updater
- 在主进程中配置:
const { autoUpdater } = require('electron-updater')
autoUpdater.checkForUpdatesAndNotify()
autoUpdater.on('update-available', () => {
mainWindow.webContents.send('update_available')
})
autoUpdater.on('update-downloaded', () => {
mainWindow.webContents.send('update_downloaded')
})
ipcMain.on('restart_app', () => {
autoUpdater.quitAndInstall()
})
使用原生模块
一些 Node.js 原生模块需要重新编译才能在 Electron 中使用:
- 安装 electron-rebuild:
npm install --save-dev electron-rebuild
- 重建模块:
./node_modules/.bin/electron-rebuild
多窗口应用
创建和管理多个窗口:
let windows = new Set()
function createWindow () {
let window = new BrowserWindow({ /* options */ })
windows.add(window)
window.on('closed', () => {
windows.delete(window)
})
return window
}
系统托盘图标
const { Tray, Menu } = require('electron')
let tray = null
app.whenReady().then(() => {
tray = new Tray('path/to/icon.png')
const contextMenu = Menu.buildFromTemplate([
{ label: 'Show', click: () => mainWindow.show() },
{ label: 'Quit', click: () => app.quit() }
])
tray.setToolTip('My App')
tray.setContextMenu(contextMenu)
})
总结
Electron 为使用 web 技术构建跨平台桌面应用提供了强大的解决方案。通过本教程,你已经学习了 Electron 的基本概念、核心 API 和最佳实践。要了解更多,可以参考 Electron 官方文档。
下一步可以探索:
- 与前端框架 (React, Vue, Angular) 集成
- 实现更复杂的 IPC 通信模式
- 构建可安装的本地插件系统
- 优化应用启动时间和内存使用
- 实现深色模式等现代 UI 功能