Electron 理解

Electron 的架构、进程模型和常用 API

问题

尽可能多的说出你对 Electron 的理解。

解答

什么是 Electron

Electron 是一个使用 Web 技术(HTML、CSS、JavaScript)构建跨平台桌面应用的框架。它将 Chromium 和 Node.js 整合到一个运行时中,让 Web 开发者可以开发 Windows、macOS、Linux 桌面应用。

进程模型

Electron 采用多进程架构,分为主进程和渲染进程:

┌─────────────────────────────────────────┐
│              Main Process               │
│  (Node.js 环境,管理应用生命周期)         │
│                                         │
│  ┌─────────────┐  ┌─────────────┐       │
│  │ BrowserWindow│  │ BrowserWindow│      │
│  └──────┬──────┘  └──────┬──────┘       │
└─────────┼────────────────┼──────────────┘
          │                │
          ▼                ▼
┌─────────────────┐ ┌─────────────────┐
│ Renderer Process│ │ Renderer Process│
│ (Chromium 渲染)  │ │ (Chromium 渲染)  │
└─────────────────┘ └─────────────────┘

主进程(Main Process)

  • 每个应用只有一个主进程
  • 运行在 Node.js 环境,可以使用所有 Node.js API
  • 负责创建和管理窗口(BrowserWindow)
  • 处理系统级操作:菜单、托盘、快捷键等

渲染进程(Renderer Process)

  • 每个窗口对应一个渲染进程
  • 运行在 Chromium 环境,负责渲染页面
  • 默认情况下无法直接访问 Node.js API(出于安全考虑)

基本项目结构

// main.js - 主进程入口
const { app, BrowserWindow } = require('electron')
const path = require('path')

function createWindow() {
  // 创建浏览器窗口
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      // 预加载脚本,在渲染进程中运行但可访问 Node.js API
      preload: path.join(__dirname, 'preload.js'),
      // 出于安全考虑,建议关闭 nodeIntegration
      nodeIntegration: false,
      // 启用上下文隔离
      contextIsolation: true
    }
  })

  // 加载页面
  win.loadFile('index.html')
}

// 应用就绪后创建窗口
app.whenReady().then(createWindow)

// 所有窗口关闭时退出应用(macOS 除外)
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

进程间通信(IPC)

主进程和渲染进程之间通过 IPC 通信:

// preload.js - 预加载脚本
const { contextBridge, ipcRenderer } = require('electron')

// 通过 contextBridge 安全地暴露 API 给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
  // 渲染进程 -> 主进程(单向)
  sendMessage: (message) => ipcRenderer.send('message', message),
  
  // 渲染进程 -> 主进程 -> 渲染进程(双向)
  invoke: (channel, data) => ipcRenderer.invoke(channel, data),
  
  // 监听主进程消息
  onUpdate: (callback) => ipcRenderer.on('update', (event, value) => callback(value))
})
// main.js - 主进程处理 IPC
const { ipcMain } = require('electron')

// 处理单向消息
ipcMain.on('message', (event, message) => {
  console.log('收到消息:', message)
})

// 处理双向调用
ipcMain.handle('invoke', async (event, data) => {
  // 处理请求并返回结果
  return { success: true, data: '处理结果' }
})

// 主进程向渲染进程发送消息
win.webContents.send('update', { version: '1.0.0' })
// renderer.js - 渲染进程使用
// 发送消息
window.electronAPI.sendMessage('Hello from renderer')

// 调用并等待结果
const result = await window.electronAPI.invoke('invoke', { id: 1 })

// 监听主进程消息
window.electronAPI.onUpdate((data) => {
  console.log('收到更新:', data)
})

常用模块

const {
  app,           // 控制应用生命周期
  BrowserWindow, // 创建和管理窗口
  Menu,          // 创建原生菜单
  Tray,          // 系统托盘
  dialog,        // 原生对话框(打开文件、保存文件等)
  globalShortcut,// 全局快捷键
  clipboard,     // 剪贴板
  shell,         // 使用默认程序打开文件/URL
  nativeImage,   // 处理图片
  Notification,  // 系统通知
  screen,        // 获取屏幕信息
  powerMonitor,  // 监控电源状态
  autoUpdater    // 自动更新
} = require('electron')

打包与分发

常用打包工具:

// package.json
{
  "scripts": {
    "build": "electron-builder"
  },
  "build": {
    "appId": "com.example.app",
    "mac": {
      "target": "dmg"
    },
    "win": {
      "target": "nsis"
    },
    "linux": {
      "target": "AppImage"
    }
  }
}

优缺点

优点

  • 跨平台:一套代码运行在 Windows、macOS、Linux
  • 开发效率高:使用熟悉的 Web 技术栈
  • 生态丰富:可使用 npm 生态和 Node.js 能力
  • 功能完整:可访问系统 API,实现原生应用功能

缺点

  • 包体积大:内置 Chromium,最小约 50MB+
  • 内存占用高:每个窗口都是独立进程
  • 性能不如原生:复杂场景可能有性能瓶颈
  • 安全性需注意:需要正确配置防止 XSS 等攻击

知名应用

VS Code、Slack、Discord、Notion、Figma Desktop、Postman 等都使用 Electron 构建。

关键点

  • 双进程架构:主进程管理应用和窗口,渲染进程负责页面渲染,通过 IPC 通信
  • 安全实践:使用 preload + contextBridge,关闭 nodeIntegration,启用 contextIsolation
  • 技术栈:Chromium(渲染)+ Node.js(系统能力)+ Web 技术(开发)
  • 适用场景:对包体积不敏感、需要快速开发跨平台桌面应用的项目
  • 性能权衡:开发效率高但资源占用大,需根据项目需求选择