知行札记
专题技术实践桌面应用实践Electron 桌面应用

Electron 工程工具与采用条件

明确脚手架、构建器、打包器、诊断和替代平台的职责。

本页整合 Electron 归档分稿中的机制、接口和接线。归档使用 Electron 44 系列作为其版本讨论背景;本文接口依据官方文档及 breaking changes 核查,实际采用时仍需固定项目版本。包版本、维护状态和原稿实测均是对应日期的历史信息。本次未启动 Electron、构建安装包、签名、公证或验证更新。代码块按各自标注区分片段与组合示例。

数据截止:2026-10-04。版本号与发布日期均来自官方渠道(npm registry、electronjs.org、GitHub API、crates.io)在原调研中的查询记录;社区二手数据(包体积、内存对比等)已明确标注。

10.1 生态全景:2026 年的 Electron 处在什么位置

截至 2026 年 10 月,Electron 最新稳定版为 44.5.1(npm 发布于 2026-09-30),对应 Chromium 152、Node.js 24.21.0;当前受支持的是 44/43/42 三条稳定线,45.0.0 已进入 alpha 阶段(数据来自 releases.electronjs.org 与 npm registry 查询)。官方节奏保持每 8 周一个主版本、紧跟 Chromium 偶数版本,并「支持最近 3 个稳定大版本」(electronjs.org timelines 文档)。

这不是一个「 dying 」的生态:electronjs.org 首页当前展示的用户名单包括 1Password、Discord、Figma、Notion、Obsidian、Slack、VS Code、Claude 等。同期,以 Tauri 2.x、Wails v3 为代表的「系统 WebView + 原生后端」路线已成为新项目选型时绕不开的对照项(见 10.7)。理解 Electron 工程化生态的现状,本质上是在回答一个问题:当你接受「每个应用内嵌一份 Chromium + Node」的成本时,你能换来怎样的开发效率、工具链成熟度与规模化验证。

10.2 脚手架与构建:Forge、electron-vite 与 electron-builder 的分工

2026 年的构建生态已形成清晰的三层分工:官方全流程工具链 Electron Forge(脚手架 + 打包 + 分发)、社区构建器 electron-vite(开发体验层)、社区打包器 electron-builder(安装包与自动更新)。

Electron Forge(@electron-forge/cli,当前 8.0.1,2026-09-30 发布)是官方文档推荐的起点,通过 npm init electron-app@latest 使用,提供 webpack / webpack-typescript / vite / vite-typescript 四个一等模板。它把 template → package(内部基于 Electron Packager)→ maker(各平台安装包)→ publisher(如 GitHub Releases)串成一条流水线。两个工程细节值得注意:Forge 在开发模式与制作分发包时自动执行 @electron/rebuild(官方文档明言);其模块解析对 symlink 不友好,Yarn ≥2 必须设 nodeLinker: node-modules,pnpm 需在 .npmrc 中设 node-linker=hoisted(Forge 官网明确说明)——这是 monorepo 集成中最常见的坑。

electron-vite(作者 Alex Wei)是当前社区事实上的开发体验标准,当前稳定版 v5.0.0(2025-12-07),v6 已进入 beta(2026 年 4 月起)。其版本演进与 Vite 强绑定:v2.0.0(2024-01)随 Electron ESM 化而支持 ESM;v3.0.0(2025-02)支持 Vite 6;v4.0.0(2025-07)升级 Vite 7 并要求 Node 20.19+/22.12+;v5.0.0 用 build.externalizeDeps、build.bytecode、isolatedEntries 配置取代旧的 externalizeDepsPlugin/bytecodePlugin,并放弃对 Electron 18–21 的构建兼容、新增对 Electron 39 的兼容目标(changelog)。核心机制:为 main / preload / renderer 三段各自建立独立 Vite 构建,renderer 走标准 dev server 获得完整 HMR;main 与 preload 修改后触发重新构建并自动重启应用(hot reload);生产构建输出到 out/,package.json 的 main 指向 ./out/main/index.js。它还内置 V8 bytecode 编译做源码保护、通过 import 后缀(?modulePath 等)支持 Worker Threads / UtilityProcess 多进程构建。脚手架 npm create @quick-start/electron@latest 提供 vanilla/Vue/React/Svelte/Solid 的 JS/TS 模板。要求 Node 20.19+/22.12+、Vite 5+。

electron-builder(当前 26.15.3,2026-06 发布)依旧是安装包格式覆盖面最广的社区方案,配套 electron-updater(6.8.9)提供 Forge 之外的自动更新实现。相比之下,曾经的基础工具 electron-packager 最新版 17.1.2 停留在 2023-08,官方路线已收敛到 Forge(npm registry 查询)。

TypeScript 与 monorepo 实践。2026 年的主流做法是「双 tsconfig」:渲染进程用标准 DOM lib,主进程/preload 用 Node 类型,并且 preload 单独一份(其全局环境同时有 DOM 与部分 Node 类型):

// tsconfig.node.json(main + preload 共用基座)
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",            // Electron 28+ 主进程支持原生 ESM
    "moduleResolution": "bundler", // 配合 Vite/Forge 的 bundler 语义
    "types": ["node"],
    "composite": true
  }
}

monorepo(pnpm workspace / Turborepo)集成要点:主进程代码必须被真实打包进应用(Forge 要求 node_modules 落盘、electron-vite 用 externalizeDeps 把依赖外置后随包分发),workspace 的 symlink 结构是打包器最常出问题的位置,因此实践中普遍采用「pnpm + node-linker=hoisted」或「electron-vite 把 workspace 包当作源码一起 bundle」两种策略(前者来自 Forge 官网,后者为 electron-vite 社区通行做法,细节待核实请以各工具最新文档为准)。

10.3 测试体系:Spectron 停维之后

Spectron 已于 2022-02-01 被官方正式弃用(官方博客《Spectron Deprecation Notice》),npm 上最后一版 19.0.0 发布于 2022-02-02,此后再无更新。官方给出的替代方案是 Playwright 与 WebdriverIO。官方对测试的总立场很坦率:「Electron doesn't actively maintain its own testing solution」(automated-testing 教程)。

Playwright 是当前社区首选。官方教程通过 _electron.launch() 以 CDP 驱动 Electron(文档原话:「experimental Electron support via Electron's support for the Chrome DevTools Protocol」),教程撰写时基于 @playwright/test@1.52,当前 Playwright 最新为 1.63.0(2026-09-04,npm 查询)。典型写法:

import { test, expect, _electron as electron } from '@playwright/test';

test('launch app', async () => {
  const app = await electron.launch({ args: ['.'] });   // 或打包后的 executablePath
  const win = await app.firstWindow();
  // 主进程内执行任意代码——这是它相对 Web 测试框架的独有能力
  const isPackaged = await app.evaluate(({ app }) => app.isPackaged);
  await expect(win.getByRole('button', { name: 'Sign in' })).toBeVisible();
  await app.close();
});

ElectronApplication.evaluate() 能直接进入主进程上下文,意味着可以对 IPC handler、窗口管理逻辑做「灰盒」断言,而不只做黑盒 UI 测试。局限同样要清楚:Electron 支持被官方标注为 experimental;对打包后应用需借助 electron-playwright-helpers 之类工具解析 out/ 产物(社区库)。

WebdriverIO 是另一条官方路线:wdio-electron-service(9.2.1,2025-10 发布)自称「Spiritual successor to Spectron」,通过 npm init wdio@latest 选择「Desktop Testing - of Electron Applications」即可,且能自动发现 Forge / electron-builder 打包产物;需要 mock Electron 原生 API(菜单、对话框)时,wdio-electron-service 的 mock 能力是相对 Playwright 的差异化优势(WebdriverIO 官方文档)。

主进程单元测试没有官方方案,社区通行做法是用 Vitest/Jest + mock electron 模块(vi.mock('electron', ...) 提供 app/BrowserWindow/ipcMain 桩),把窗口逻辑与业务逻辑解耦后仅测业务部分——此为社区实践归纳,官方文档未覆盖。官方教程还给出第三条路:自定义 test driver,用 child_process.spawn 以 stdio: 'ipc' 启动应用,自建驱动「开销更低、可暴露自定义方法」,VS Code 的 smoke test 即此类思路(前者出自官方教程,后者为该项目公开实践)。

E2E 组织建议:按「进程分层」而非「页面」组织——主进程纯逻辑下沉为单测;IPC 契约用类型共享 + 单测覆盖;Playwright 只保留关键用户旅程,并利用 evaluate 做主进程状态断言以减少脆弱的选择器。

10.4 原生 Node 模块:ABI、rebuild 与 prebuild

原理:Electron 内置的 Node 与系统 Node ABI 不一致(官方文档举例:Chromium 的 BoringSSL 取代 OpenSSL),因此原生模块必须针对 Electron 重新编译,否则启动即报 NODE_MODULE_VERSION 不匹配错误。三条安装路径(官方文档《Native Node Modules》):

  1. @electron/rebuild(当前 4.2.0,2026-07 发布):npm i -D @electron/rebuild && ./node_modules/.bin/electron-rebuild,自动探测 Electron 版本、下载 headers 并重编;每次 npm install 后都需要重跑;使用 Forge 时该步骤自动执行。调试原生模块时可加 --debug。
  2. prebuild:模块若发布了 Electron 预编译二进制,则不要设置 --build-from-source / npm_config_build_from_source,以直接复用预编译产物。
  3. node-pre-gyp:若缺少 Electron 二进制则只能源码编译,官方建议对这类模块改用 @electron/rebuild。

2026 年的实践共识:优先选择基于 Node-API 的原生依赖(Node-API 以稳定的 C ABI 为目标,跨 Node/Electron 版本无需重编),better-sqlite3、sharp 等主流库均已提供 prebuild + Electron 目标;确需自研原生模块时,Node-API 是唯一推荐的接口(此为 Node 官方长期方向与社区共识,Electron 该文档页未展开论述)。打包层面,原生模块不能被 bundle(electron-react-boilerplate 文档明确将其作为 webpack externals 处理),需随 node_modules 一起进入分发包。重 CPU 任务如今更多改用 utilityProcess(Electron 22 引入的官方 API,官方博客):由 Chromium Services 启动的带 Node 的子进程,API 对齐 child_process.fork,可与沙箱渲染进程通过 MessageChannel 直连,这为「把原生依赖隔离在 utility 进程」提供了官方姿势。

10.5 官方与社区周边库现状(2026-10 原调研 npm 查询记录)

库最新版(发布日)现状要点
electron-store11.0.2(2025-10-05)要求 Electron 30+;纯 ESM、不再提供 CJS;渲染进程因 sandbox: true 默认无法直接使用,README 明确建议「主进程持有 store,经 IPC 暴露」
@electron/remote2.1.3(2025-07-07)内置 remote 模块(Electron 14 移除)的官方接替者;仅作迁移期的过渡,新代码不应引入
electron-log5.4.4(2026-05-14)活跃维护;主/渲染进程统一日志、文件轮转、多 transport
electron-builder / electron-updater26.15.3(2026-06)/ 6.8.9(2026-06)社区主流打包 + 自动更新组合
@electron/notarize3.1.1(2025-10-31)macOS 公证
@electron/fuses2.1.3(2026-06-29)运行时开关(e.g. enableNodeCliInspectArguments: false)加固
@electron/universal3.0.6(2026-07-02)macOS 通用二进制合并
wdio-electron-service9.2.1(2025-10-24)Spectron 精神续作
electron-redux2.0.0(2024-10-02)跨进程 Redux 同步(Slack 架构同源思路),更新缓慢

一个值得注意的信号:官方 @electron/* 命名空间(rebuild、fuses、notarize、universal、remote)吸收了原 userland 工具,而老牌 electron-packager 已停滞——核心链路向官方收敛是近两年生态的主旋律。

10.6 大型 Electron 应用架构案例

VS Code(公开程度最高的样本)。官方 wiki《Source Code Organization》给出了教科书级的分层:src/vs/ 下按 base(通用工具)→ platform(服务与依赖注入)→ editor(Monaco 核心)→ workbench(工作台)→ code(Electron 入口)分层,每层内部再按运行环境切目录:common(纯 JS)/ browser / node / electron-browser / electron-utility / electron-main,并规定严格的依赖方向(如 electron-main 可依赖 node/electron-utility,反之不行)。这套「层 × 环境」矩阵是它能把同一份代码跑在桌面、Web 与远程(server)上的根基;workbench.desktop.main.ts 与 workbench.web.main.ts 分入口共享 workbench.common.main.ts。进程模型:主进程之外,每个窗口一个 renderer、独立 Extension Host 进程跑全部扩展、shared process 承担跨窗口服务,语言服务经 LSP 外置——扩展崩溃不拖垮编辑器(官方 wiki 与文档)。背景数据:2025 Stack Overflow 开发者调查中 75.9% 受访者使用 VS Code(Wikipedia 引述)。

Slack。工程博客三部曲至今仍是大型 Electron 重构的最佳公开材料:《When a rewrite isn't: rebuilding Slack on the desktop》(2019)记录了为解决「一个 workspace 一个进程」的内存问题而做的整体重写——React + Redux + RxJS + TypeScript,引入 electron-redux 让每个进程各持一个 store、经 IPC 同步;《Growing Pains: Migrating Slack's Desktop App to BrowserView》记录从 <webview> 迁到 BrowserView 的动机(性能/可靠性)与代价;《Interop's Labyrinth》则系统对比了 web 与桌面共享代码的四种模式(The Shortcut / Remote Isolation / Local Resources / Hybrid)。近期文章(2025-04《How Slack Rebuilt Notifications》、2026-03《A unified notifications model across desktop and mobile》)显示其仍在持续演进桌面架构。

Figma。官方博客《Introducing BrowserView for Electron》明确「桌面端押注 Electron」,并作为上游贡献者把 BrowserView API 推进了 Electron;其性能策略不在框架而在渲染层——画布完全 WebGL 渲染并推出 WebAssembly 版本(同一文)。「框架标准化 + 自研渲染引擎」是重交互应用的标准打法。

1Password 8。官方博客《1Password 8: The Story So Far》(2021-08)披露其核心架构:跨全平台(macOS/Windows/Linux/iOS/Android/浏览器/Web)的共享后端 Core 用 Rust 编写;官方论坛进一步确认桌面端是 hybrid app——「后端 core 用 Rust,前端 TypeScript + React,用 Electron 打包」,三个桌面平台是同一个 Electron 应用(1Password 官方人员发言)。这是「Rust 核心 + Electron 壳」混合架构的代表。

Obsidian。基于 Electron(官方 apps 列表收录;官方论坛历次升级公告可见 Electron 版本变迁,如 0.13.30 因 Electron 13→16 要求重新下载;Arch Linux 官方仓库的 obsidian 包依赖 electron30)。其架构细节未系统公开——待核实。

Discord。桌面端基于 Electron(官方 apps 列表),但近年公开工程文章集中于服务端(如《Why Discord is switching from Go to Rust》,2020,为 Read States 服务而非桌面端);桌面端内部架构的权威公开资料目前缺乏——待核实,不宜引用社区转述。

10.7 与 Tauri、Wails 的定位对比与 2026 选型

两个框架的共同思路:不内嵌 Chromium,用 OS 原生 WebView(Windows: WebView2;macOS: WKWebView;Linux: WebKitGTK)+ Rust/Go 后端。Tauri 2.0 于 2024-10-02 发布稳定版(官方博客),带来 iOS/Android 移动端支持、插件化核心、permissions/scopes/capabilities 权限体系;当前 2.x 稳定线为 2.12.1(2026-09-30,crates.io),3.0.0-alpha 开发中(2026-09 起),路线图上出现 CEF-for-Linux 备选与 Servo(Verso)实验(官方博客)。Wails(Go 后端)当前 v3 处于 beta(v3.0.0-beta.27,2026-10-01,GitHub API),v2 仍在维护(二手资料称 v2 稳定线为 2.x,具体版本待核实)。

维度Electron 44Tauri 2.xWails v2/v3-beta
后端语言Node.jsRustGo
Web 引擎自带 Chromium(版本锁定)系统 WebView系统 WebView
渲染一致性三个平台完全一致依赖各平台 WebView(存在差异)同左
安装包/内存大(社区基准普遍报 80–150 MB 量级)小(社区基准 2.5–10 MB)小(官方自称 ~15 MB,待独立核实)
移动端无iOS/Android(2.0 起)无
Node 原生生态完整无(Rust crate 生态)无(Go 生态)
测试工具链Playwright/WDIO 成熟需 WebDriver 驱动 WebView相对薄弱
典型代表VS Code、Slack、Figma、1Password、Obsidian新兴工具类应用较多Go 技术栈团队

(包体/内存数字来自社区基准(digitalapplied、Elanis/web-to-desktop-framework-comparison 等),量级可信但随应用差异极大,选型时应自行实测;星标数可参考 Elanis 维护的对比仓库:Electron ~122.9k、Tauri ~110.8k、Wails ~36.1k。)

2026 年的选型讨论可以概括为三条判断:①WebView 一致性是 Tauri/Wails 的结构性代价——Linux WebKitGTK 与 Windows WebView2 的行为差异是真实工程成本,Tauri 官方把「CEF for Linux 备选」写上路线图本身就是对此的回应;②重前端/重 Node 生态的应用留在 Electron——需要 puppeteer 类能力、Node 原生模块、CDP 级测试与完全一致的渲染时,Electron 仍是默认解;③Tauri 的真实优势场景是「小工具 + 移动端同构 + Rust 团队」,其权限模型对安全敏感应用有额外吸引力。1Password 的案例还提示了第四条路:核心用 Rust 重写、壳留 Electron,先解决计算密度与安全边界,再谈框架替换。

10.8 常见坑与反模式(2026 仍高频)

  1. 把 nodeIntegration: true 当快捷方式:现代默认(nodeIntegration: false、sandbox: true、contextIsolation: true)下,electron-store 等依赖 Node 内置的库在渲染进程/preload 直接 import 会报 Can't resolve 'fs',正确做法是主进程持有、IPC 暴露(electron-store README)。
  2. @electron/remote 长期驻留:它只是迁移桥,持久使用等于重新引入安全与序列化开销(官方在移除内置 remote 时的立场)。
  3. ESM 半迁移:Electron 28+ 主进程支持 ESM,但 ESM 是异步加载——app.ready 前只有入口 import 的副作用已执行,需「在 ready 前 generously await」;ESM preload 必须 .mjs 且沙箱 preload 根本不能用 ESM import(须 CJS/bundle)。转译产物(Babel/TS 输出 require)与原生 ESM 的时序不同,迁移期最易踩(官方 ESM 文档)。
  4. monorepo symlink 打包失败:Forge 对 symlink/PnP 的解析是「naive」的(官网原话),务必 node-linker=hoisted。
  5. 原生模块被 bundler 吞掉:原生 .node 二进制不能进 bundle,必须 externalize 并随包分发;npm install 后忘记重跑 electron-rebuild 是「昨天还好好的」类报错的头号来源(官方文档)。
  6. 在 renderer 里做重活:CPU 密集任务应下沉 utilityProcess(Electron 22+)或 worker,而不是 Promise 队列——Slack 与 VS Code 的进程拆分都是同一条原则的放大版。
  7. 测试金字塔倒置:Spectron 时代遗留的「全靠 E2E」思路在 Playwright 下依旧昂贵;主进程逻辑单测化(见 10.3)是 2026 年的分界线。

参考来源

最后更新于

本页目录