MD 状态:已引入 更新:2026/5/12

🏗️ 架构设计:Project Knowledge Base/桌面与跨平台UI/Electron 架构设计

Electron

用 JavaScript、HTML、CSS 构建跨平台桌面应用的最成熟框架,基于 Chromium + Node.js,VS Code、Slack、Discord 都用它。

🎯 为什么需要它

如果你想用已有的 Web 技术栈(React/Vue/Svelte)开发桌面应用,Electron 是最成熟、生态最完善的选择。它让前端开发者无需学习新语言就能构建原生桌面应用,且跨平台渲染完全一致。

✅ 核心优势

  • 极成熟的生态:10 年+ 生产验证,VS Code/Slack/Discord/Notion/Figma 桌面端都基于 Electron
  • 渲染一致性:捆绑 Chromium,Windows/macOS/Linux 上表现完全一致,无 WebView 兼容问题
  • 全 Node.js 生态:可直接使用 npm 上所有包(better-sqlite3、node-pty、ffi-napi 等原生模块)
  • 开发体验极佳:Hot Reload、DevTools、丰富的调试工具,构建速度快(JS 工具链)
  • 零语言门槛:纯 JavaScript/TypeScript,无需学习 Rust 或 Swift
  • 自动更新成熟:electron-updater 支持 GitHub Releases/S3/自定义服务器,支持增量更新

⚡ 性能表现

指标ElectronTauri说明
安装包100-200MB3-10MBChromium 体积大
空闲内存150-300MB30-50MB每窗口一个 Chromium 实例
工作内存320-520MB85-120MB复杂应用差距更大
冷启动1-3s0.3-1sChromium 初始化耗时
构建速度JS 工具链 vs Rust 编译
CPU 使用正常正常差距不大

适用规模:中小型桌面应用表现良好,超大型应用(数百个窗口)需注意内存管理。

🚀 快速上手

环境准备

  • Node.js 18+
  • npm / yarn / pnpm

创建项目

# 方式一:手动创建
mkdir my-electron-app && cd my-electron-app
npm init -y
npm install electron --save-dev

# 方式二:使用 Electron Forge(推荐)
npm create electron-app@latest my-app -- --template=webpack-typescript

# 方式三:使用 electron-vite
npm create @quick-start/electron my-app -- --template react-ts

项目结构

my-electron-app/
├── package.json          # "main": "main.js"
├── main.js               # Main Process(Node.js 后端)
├── preload.js            # Preload Script(安全桥接)
├── index.html            # Renderer(前端页面)
├── renderer.js           # Renderer 逻辑
└── src-tauri/            # (如果用 electron-builder)
    └── icon.png

最小可运行示例

package.json

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron": "^42.0.0"
  }
}

main.js(Main Process):

const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const path = require('path');

function createWindow() {
  const win = new BrowserWindow({
    width: 1024,
    height: 768,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,    // 必须开启
      nodeIntegration: false     // 必须关闭
    }
  });

  win.loadFile('index.html');
}

// IPC 处理
ipcMain.handle('get-version', () => app.getVersion());

ipcMain.handle('show-dialog', async () => {
  const result = await dialog.showMessageBox({
    message: 'Hello from Electron!',
    type: 'info'
  });
  return result.response;
});

app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

preload.js(安全桥接):

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  getVersion: () => ipcRenderer.invoke('get-version'),
  showDialog: () => ipcRenderer.invoke('show-dialog'),
  platform: process.platform
});

index.html(Renderer):

<!DOCTYPE html>
<html>
<body>
  <h1>My Electron App</h1>
  <button id="version">获取版本</button>
  <button id="dialog">弹出对话框</button>
  <p id="output"></p>

  <script>
    document.getElementById('version').addEventListener('click', async () => {
      const version = await window.electronAPI.getVersion();
      document.getElementById('output').textContent = `Electron v${version}`;
    });

    document.getElementById('dialog').addEventListener('click', async () => {
      await window.electronAPI.showDialog();
    });
  </script>
</body>
</html>

运行

npm start

📦 常用功能速查

窗口管理

const { BrowserWindow, BrowserView } = require('electron');

// 创建窗口
const win = new BrowserWindow({
  width: 1200,
  height: 800,
  minWidth: 800,
  minHeight: 600,
  title: 'My App',
  icon: './icon.png',
  frame: false,           // 无边框窗口
  transparent: true,      // 透明窗口
  alwaysOnTop: true,      // 置顶
  fullscreenable: true,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
    contextIsolation: true,
    nodeIntegration: false
  }
});

// 加载内容
win.loadFile('index.html');
win.loadURL('https://example.com');

// 窗口操作
win.minimize();
win.maximize();
win.hide();
win.show();
win.focus();
win.setFullScreen(true);

// 无边框窗口拖拽(CSS)
// <div style="-webkit-app-region: drag;">可拖拽区域</div>

应用菜单

const { Menu } = require('electron');

const template = [
  {
    label: '文件',
    submenu: [
      { label: '新建', accelerator: 'CmdOrCtrl+N', click: () => {} },
      { label: '打开', accelerator: 'CmdOrCtrl+O', click: () => {} },
      { type: 'separator' },
      { role: 'quit' }
    ]
  },
  {
    label: '编辑',
    submenu: [
      { role: 'undo' },
      { role: 'redo' },
      { type: 'separator' },
      { role: 'cut' },
      { role: 'copy' },
      { role: 'paste' }
    ]
  },
  {
    label: '视图',
    submenu: [
      { role: 'reload' },
      { role: 'toggleDevTools' },
      { type: 'separator' },
      { role: 'zoomIn' },
      { role: 'zoomOut' },
      { role: 'resetZoom' }
    ]
  }
];

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);

系统托盘

const { Tray, Menu, nativeImage } = require('electron');

let tray;

app.whenReady().then(() => {
  const icon = nativeImage.createFromPath('./tray-icon.png');
  tray = new Tray(icon);
  tray.setToolTip('My App');

  const contextMenu = Menu.buildFromTemplate([
    { label: '打开主窗口', click: () => mainWindow.show() },
    { type: 'separator' },
    { label: '退出', role: 'quit' }
  ]);

  tray.setContextMenu(contextMenu);

  tray.on('click', () => {
    mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
  });
});

文件对话框

const { dialog } = require('electron');

// 打开文件
const result = await dialog.showOpenDialog({
  properties: ['openFile', 'multiSelections'],
  filters: [
    { name: 'Images', extensions: ['png', 'jpg', 'gif'] },
    { name: 'All Files', extensions: ['*'] }
  ]
});
if (!result.canceled) {
  console.log(result.filePaths);
}

// 保存文件
const saveResult = await dialog.showSaveDialog({
  defaultPath: 'document.txt',
  filters: [{ name: 'Text', extensions: ['txt'] }]
});

// 消息框
await dialog.showMessageBox({
  type: 'info',
  title: '提示',
  message: '操作完成',
  buttons: ['确定']
});

通知

const { Notification } = require('electron');

new Notification({
  title: '任务完成',
  body: '文件已成功下载',
  icon: './icon.png'
}).show();

全局快捷键

const { globalShortcut } = require('electron');

app.whenReady().then(() => {
  globalShortcut.register('CommandOrControl+Shift+X', () => {
    console.log('快捷键触发');
  });
});

app.on('will-quit', () => {
  globalShortcut.unregisterAll();
});

自动更新(electron-updater)

const { autoUpdater } = require('electron-updater');

autoUpdater.autoDownload = true;
autoUpdater.autoInstallOnAppQuit = true;

autoUpdater.on('update-available', (info) => {
  console.log(`新版本: ${info.version}`);
});

autoUpdater.on('update-downloaded', (info) => {
  dialog.showMessageBox({
    type: 'info',
    title: '更新就绪',
    message: `版本 ${info.version} 已下载,重启应用以完成更新`,
    buttons: ['立即重启', '稍后']
  }).then(({ response }) => {
    if (response === 0) autoUpdater.quitAndInstall();
  });
});

// 启动时检查更新
app.whenReady().then(() => {
  autoUpdater.checkForUpdatesAndNotify();
});

electron-builder 配置package.json):

{
  "build": {
    "appId": "com.example.myapp",
    "productName": "My App",
    "mac": {
      "category": "public.app-category.developer-tools",
      "target": ["dmg", "zip"]
    },
    "win": {
      "target": ["nsis"]
    },
    "linux": {
      "target": ["AppImage", "deb"]
    },
    "publish": {
      "provider": "github",
      "owner": "your-org",
      "repo": "your-app"
    }
  }
}

数据持久化

// 方式一:electron-store(推荐)
const Store = require('electron-store');
const store = new Store();

store.set('settings.theme', 'dark');
store.get('settings.theme');  // 'dark'

// 方式二:SQLite
const Database = require('better-sqlite3');
const db = new Database('app.db');
db.exec('CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, content TEXT)');

原生模块使用

# 安装原生模块(需要编译环境)
npm install better-sqlite3 keytar node-pty
// 在 Main Process 中使用
const Database = require('better-sqlite3');
const db = new Database('my.db');

// 在 Preload 中安全暴露
contextBridge.exposeInMainWorld('dbAPI', {
  getNotes: () => ipcRenderer.invoke('get-notes'),
  addNote: (content) => ipcRenderer.invoke('add-note', content)
});

📋 关键配置项

BrowserWindow webPreferences

webPreferences: {
  preload: path.join(__dirname, 'preload.js'),
  contextIsolation: true,      // 安全隔离(默认 true)
  nodeIntegration: false,      // 禁用 Node.js(默认 false)
  sandbox: true,               // 启用沙箱(推荐)
  webSecurity: true,           // 启用同源策略(默认 true)
  allowRunningInsecureContent: false,
  experimentalFeatures: false,
  webviewTag: false            // 禁用 webview 标签(安全)
}

📦 适用场景

适合:

  • 已有 Web 前端的团队想快速出桌面应用
  • 需要完全一致的跨平台渲染表现
  • 重度依赖 Node.js 原生模块(better-sqlite3、node-pty 等)
  • IDE/编辑器类应用(VS Code 就是 Electron)
  • 团队纯 JS/TS 技术栈,无 Rust/Swift 经验
  • 需要成熟的自动更新和分发方案

不适合:

  • 对安装包大小极度敏感(>100MB 起步)
  • 内存受限环境(低配设备、嵌入式)
  • 需要移动端支持(Electron 无移动端)
  • 安全敏感应用(攻击面较大,需严格配置)

⚠️ 已知坑 & 注意事项

  • 体积大:捆绑 Chromium 导致安装包 100-200MB,多应用共存时每个都带一份 Chromium
  • 内存占用高:每个窗口一个 Chromium 进程,开 5 个窗口轻松吃 1GB+ 内存
  • 安全配置必须严格contextIsolation: true + nodeIntegration: false 是底线,否则 XSS 可直接 RCE
  • 原生模块兼容性:每个 Electron 大版本升级可能导致原生模块(better-sqlite3 等)需要重新编译
  • macOS 签名和公证:分发给非开发者需要 Apple 开发者账号(99 EUR/年),否则用户会看到”未验证开发者”警告
  • 自动更新边界情况:Windows 需管理员权限、macOS 需签名公证、Linux AppImage 自更新有坑
  • CVE 安全漏洞:2026 年 4 月发现 CVE-2026-34779(macOS moveToApplicationsFolder RCE)和 CVE-2026-34765(window.open 隔离绕过),必须及时更新
  • BrowserWindow 泄漏:未正确关闭窗口会导致内存泄漏,务必在 window-all-closed 事件中清理

🆚 竞品对比

维度ElectronTauriFlutter DesktopNeutralino
语言JS/TSRust + JS/TSDartJS/TS
渲染Chromium 捆绑系统 WebView自绘引擎系统 WebView
安装包100-200MB3-10MB20-50MB1-2MB
内存150-300MB30-50MB100-200MB20MB
渲染一致性完全一致有差异完全一致有差异
生态极成熟成长期成熟早期
移动端iOS+AndroidiOS+Android
学习曲线中(需 Rust)中(需 Dart)
原生模块npm 全支持有限有限有限

选择建议:

  • 已有 Web 团队 + 需要最大兼容性 + 不关心体积 → Electron
  • 新项目 + 能接受 Rust + 要小体积 → Tauri
  • 已有 Flutter 移动端 → Flutter Desktop
  • 极致轻量 + 简单应用 → Neutralino

🌍 生态 & 社区

  • 维护状态:极活跃,跟随 Chromium 每 8 周发布大版本,当前最新 v42(Chromium 148, Node v24.15.0)
  • 文档质量:优秀,官方文档详尽,教程和示例丰富
  • 周边生态
    • electron-builder — 最流行的打包工具
    • Electron Forge — 官方推荐的构建工具链
    • electron-vite — Vite 集成,启动更快
    • electron-store — 简单的持久化存储
    • electron-updater — 自动更新
    • electron-log — 日志记录
    • @electron/fuses — 安全开关配置
  • 社区活跃度:115k+ Stars,Discord 社区活跃,StackOverflow 问题丰富

💡 引入评估

维度评分(/5)备注
上手难度⭐⭐⭐⭐⭐前端开发者零门槛
文档完善度⭐⭐⭐⭐⭐10 年积累,极其完善
社区活跃⭐⭐⭐⭐⭐115k Stars,最大桌面框架社区
性能⭐⭐⭐体积大、内存高是硬伤
稳定性⭐⭐⭐⭐成熟稳定,但需关注安全更新
综合⭐⭐⭐⭐成熟可靠,但有性能代价

结论:推荐使用 — Electron 是 Web 技术栈构建桌面应用的最成熟选择。如果你的团队是纯 JS/TS 技术栈,且对应用体积和内存不是极度敏感,Electron 是最安全的选择。如果追求极致性能和小体积,建议评估 Tauri。

推荐引入版本v42.x(Chromium 148, Node v24.15.0,避免使用 latest)

🔗 相关链接

📝 个人备注

(留白,供后续补充实际使用心得)