Electron 详细教程

Electron 是一个使用 JavaScript, HTML 和 CSS 构建跨平台桌面应用程序的框架。它结合了 Chromium 渲染引擎和 Node.js 运行时,让你可以使用 web 技术开发原生桌面应用。

目录

  1. Electron 简介
  2. 环境准备
  3. 创建第一个 Electron 应用
  4. 项目结构
  5. 主进程与渲染进程
  6. 进程间通信
  7. 原生 API 使用
  8. 打包与分发
  9. 安全最佳实践
  10. 调试与性能优化
  11. 高级特性

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 应用

  1. 创建项目文件夹并初始化:
mkdir my-electron-app
cd my-electron-app
npm init -y
  1. 安装 Electron 作为开发依赖:
npm install electron --save-dev
  1. 创建 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()
  }
})
  1. 创建 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

  1. 修改 package.json,添加启动脚本:
{
  "name": "my-electron-app",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron": "^latest"
  }
}
  1. 启动应用:
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 提供了 ipcMainipcRenderer 模块来实现主进程和渲染进程间的通信。

基本 IPC 通信

  1. 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'
})
  1. 在渲染进程 (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。推荐使用预加载脚本暴露特定功能:

  1. 创建 preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
  sendMessage: (message) => ipcRenderer.send('message', message),
  onReply: (callback) => ipcRenderer.on('reply', callback)
})
  1. 修改 main.js 中的 BrowserWindow 配置:
new BrowserWindow({
  webPreferences: {
    preload: path.join(__dirname, 'preload.js')
  }
})
  1. 在渲染进程中通过暴露的 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 打包

  1. 安装 electron-builder:
npm install electron-builder --save-dev
  1. 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"
  }
}
  1. 运行打包命令:
npm run dist

打包完成后,安装包会生成在 dist 目录中。

打包配置选项

  • target:指定打包格式 (nsis, zip, dmg, AppImage 等)
  • icon:应用图标
  • extraResources:包含额外资源文件
  • asar:是否将应用打包为 asar 归档
  • publish:自动更新配置

安全最佳实践

  1. 启用上下文隔离:防止渲染进程直接访问 Node.js API
  2. 使用预加载脚本:仅暴露必要的 API
  3. 禁用 Node.js 集成:对于不需要 Node.js 功能的渲染进程
  4. 验证 IPC 消息:不信任渲染进程发送的消息
  5. 使用 CSP:内容安全策略限制加载的资源
  6. 更新依赖:保持 Electron 和所有依赖项更新

示例安全配置:

new BrowserWindow({
  webPreferences: {
    nodeIntegration: false,
    contextIsolation: true,
    enableRemoteModule: false,
    preload: path.join(__dirname, 'preload.js')
  }
})

调试与性能优化

调试主进程

  1. 使用 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"
    }
  ]
}
  1. 使用 Chrome 开发者工具:
mainWindow.webContents.openDevTools()

性能优化建议

  1. 减少 DOM 复杂度:简化页面结构
  2. 使用懒加载:延迟加载非关键资源
  3. 优化图像:压缩和适当缩放图像
  4. 避免同步操作:特别是在主进程中
  5. 使用 Web Workers:处理 CPU 密集型任务
  6. 分析性能:使用 Chrome 开发者工具的性能面板

高级特性

自动更新

  1. 安装 electron-updater:
npm install electron-updater
  1. 在主进程中配置:
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 中使用:

  1. 安装 electron-rebuild:
npm install --save-dev electron-rebuild
  1. 重建模块:
./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 功能









results matching ""

    No results matching ""