Electron 应用在 Windows on Arm 上的构建与分发实战指南
本指南面向需要在 ARM64 架构 Windows 设备(如基于骁龙处理器的 Windows 10/11 设备)上运行 Electron 应用的开发者。从 Electron 6.0.8 起即可为 Windows on Arm 构建应用,但需要处理架构判定、原生模块重编译、交叉编译工具链等系列问题。读完本文,你将掌握一套从开发机交叉编译到真机调试的完整 Windows on Arm 构建流程。
前提与适用范围
本文基于当前仓库的 docs/tutorial/windows-arm.md 编写。原文面向 Electron 6.0.x 时期的 Windows on Arm 支持生态,其描述的架构判定问题、原生模块重编译要求、交叉编译方法论以及 Chromium 沙箱行为等核心知识点,在今天依然适用于所有为 ARM64 Windows 打包 Electron 应用的场景。
需要特别说明的是,Windows on Arm 平台(x86_64 应用经模拟运行)在 Electron 时代早期性能损失明显,而原生 ARM64(arm64)二进制无需模拟、直接以原生速度运行,这也是该文档强调"为 arm64 重新编译一切"的根本原因。自 Electron 6.0.8 起即可将应用构建为 Windows 10 on Arm 的原生版本,这能显著改善性能,但代价是:
- 应用中使用的任何原生 Node 模块都必须重新编译;
- 构建与打包脚本可能需要进行小幅修正(主要是架构判定逻辑);
- 需要一套与 x86/x64 不同的交叉编译工具链。
运行一个最简应用
如果你的应用不使用任何原生模块,生成 ARM64 版本的过程非常简单,只需三步:
- 确保应用目录下的
node_modules为空(避免沿用旧架构的产物)。 - 在 命令提示符(Command Prompt)中,先执行
set npm_config_arch=arm64,再像往常一样运行npm install/yarn install。 - 如果你把 Electron 作为开发依赖安装(参见 tutorial-2-first-app.md 的初始化 npm 项目部分),npm 会据此下载并解压 arm64 版本的 Electron 二进制。之后即可照常打包与分发你的应用。
环境变量生效的底层原理
为什么一个 npm_config_arch=arm64 就能让 npm 下载到正确架构的 Electron?答案在仓库的 npm/install.js 中:
const platform = process.env.ELECTRON_INSTALL_PLATFORM || process.env.npm_config_platform || process.platform;
let arch = process.env.ELECTRON_INSTALL_ARCH || process.env.npm_config_arch || process.arch;
Electron 的 npm 安装脚本(postinstall)在下载预编译二进制时,按以下优先级决定目标架构:
ELECTRON_INSTALL_ARCH环境变量(最高优先级,支持electron .、npm install等多种调用方式,详见 docs/api/environment-variables.md);npm_config_arch(即npm install --arch=arm64或set npm_config_arch=arm64写入的环境变量);- 当前进程的
process.arch(兜底,即运行 npm 的机器自身架构)。
随后安装脚本调用 downloadArtifact(@electron/get)以该 arch 下载对应架构的 zip 包,解压并写入指向 electron.exe 的 path.txt。也就是说:只要让 npm_config_arch(或 ELECTRON_INSTALL_ARCH)等于 arm64,npm 安装 Electron 这一依赖时就会自动拉取 Windows on Arm 的二进制,与应用代码本身无关。
补充:官方支持的目标架构集合可参考 docs/tutorial/installation.md,其中明确列出
arm64对应 "Apple silicon, Windows on ARM, ARM64 Linux",与本文讨论的 Windows on Arm 场景一致。
通用注意事项
架构相关代码的判定陷阱
大量 Windows 专属代码中存在着在 x64 与 x86 之间二选一的 if...else 逻辑:
if (process.arch === 'x64') {
// 64 位逻辑...
} else {
// 32 位逻辑...
}
如果要支持 arm64,这类写法几乎必然命中错误分支:arm64 既不是 x64,也不是"else"里隐含假设的 x86。因此需要仔细排查应用代码与构建脚本中所有类似的条件判断。在自定义构建与打包脚本中,应始终检查环境变量 npm_config_arch,而不是依赖当前运行进程的 process.arch——后者反映的是"脚本正在哪台机器上跑",前者才是"目标产物面向哪种架构"。仓库中真实存在大量基于 process.platform === 'win32' 的分支代码(如 lib/browser/api/auto-updater.ts、lib/common/init.ts),这提醒开发者:平台与架构判断散落在代码各处的项目,在迁移到 arm64 时必须系统性检索。
原生模块
若使用原生模块,必须确保它们使用 MSVC v142 工具集编译(即 Visual Studio 2017 提供)。同时要逐一核对:原生模块自带或引用的预编译 .dll / .lib 是否提供 Windows on Arm 版本。很多原生模块通过 node-pre-gyp / prebuild 分发预编译产物,若发布者未产出 win32-arm64 的二进制,就需要按后文的交叉编译流程从源码自行编译。
测试你的应用
在真机测试时请注意:
- 使用运行 Windows 10(1903 或更高版本)的 Windows on Arm 设备;
- 务必将整个应用目录复制到目标设备本地磁盘后再运行。
最后一点很关键:Chromium 的沙箱在从网络位置(UNC 路径、共享目录)加载应用资源时无法正常工作。这与 docs/tutorial/security.md 中反复强调的沙箱工作原理一脉相承——沙箱要求进程与其资源具备本地、可控的访问边界。
开发环境准备
Node.js / node-gyp
官方建议使用 Node.js v12.9.0 或更高版本(该版本起内置了对 ARM64 原生模块编译所需变更的 node-gyp)。如果无法升级 Node,可以手动把 npm 内置的 node-gyp 更新到 5.0.2 或更高版本,该版本同样包含为 Arm 编译原生模块所需的关键改动。
对当前 Electron 源码树而言,仓库以 node-gyp 12.x 作为开发依赖(见 package.json),并在 script/nan-spec-runner.js 等测试脚本中显式向子进程注入 npm_config_arch 环境变量以控制目标架构——这说明通过环境变量把 arch 贯穿到 node-gyp 整个编译链路,正是官方测试自身也在依赖的标准机制。
Visual Studio 2017
交叉编译原生模块需要 Visual Studio 2017(任意版本)。建议通过微软 Visual Studio Dev Essentials 计划获取 Community 2017。安装后,在 命令提示符 中运行以下命令补装 ARM 相关组件:
vs_installer.exe ^
--add Microsoft.VisualStudio.Workload.NativeDesktop ^
--add Microsoft.VisualStudio.Component.VC.ATLMFC ^
--add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^
--add Microsoft.VisualStudio.Component.VC.MFC.ARM64 ^
--includeRecommended
各参数含义:
| 组件 ID | 用途 |
|---|---|
Microsoft.VisualStudio.Workload.NativeDesktop |
使用 C++ 的桌面开发工作负载(基础编译工具) |
Microsoft.VisualStudio.Component.VC.ATLMFC |
ATL / MFC 运行库(若原生模块依赖 MFC) |
Microsoft.VisualStudio.Component.VC.Tools.ARM64 |
ARM64 目标编译器与工具集(交叉编译的关键) |
Microsoft.VisualStudio.Component.VC.MFC.ARM64 |
面向 ARM64 的 MFC 组件 |
创建交叉编译命令提示符
这里有一个容易踩坑的细节:设置 npm_config_arch=arm64 确实会让编译器产出正确的 arm64 .obj 文件,但标准的 Developer Command Prompt for VS 2017(开发人员命令提示符)默认使用 x64 链接器,链接阶段仍会失败。解决办法是创建一个专用的交叉编译提示符:
- 在开始菜单中找到 x64_x86 Cross Tools Command Prompt for VS 2017 快捷方式,右键选择 打开文件位置,把该快捷方式复制一份到方便的位置。
- 右键新快捷方式,选择 属性。
- 将 目标(Target)字段末尾的
vcvarsamd64_x86.bat改为vcvarsamd64_arm64.bat。
启动成功后,提示符会打印类似如下的信息:
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.15
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64_arm64'
最后一行 Environment initialized for: 'x64_arm64' 是判断交叉编译环境是否就绪的关键标志。
若你想直接在 Windows on Arm 设备上开发,则将 目标 字段替换为 vcvarsx86_arm64.bat——这样可借助设备的 x86 模拟(Windows on Arm 的 x86 仿真)完成交叉编译。
链接正确的 node.lib
这是原生模块交叉编译中最常见的"静默失败"点。默认情况下,node-gyp 会解压 Electron 的 node 头文件,并把 x86 与 x64 版 node.lib 下载到 %APPDATA%\..\Local\node-gyp\Cache,但不会下载 arm64 版本(此问题官方已有跟踪修复)。手工补救方法:
- 从 Electron 官方 headers 分发地址下载 arm64 版
node.lib(对应目录结构形如v6.0.9/win-arm64/node.lib)。 - 将其移动到
%APPDATA%\..\Local\node-gyp\Cache\6.0.9\arm64\node.lib。
其中 6.0.9 需替换为你实际使用的 Electron 版本。node.lib 是原生模块在链接阶段必须导入的"Electron 导出符号表",如果缺失或架构不符,链接器会报出大量未解析外部符号或架构不匹配错误。
交叉编译原生模块
完成上述全部准备后,进入交叉编译环节:
- 打开上一节创建的交叉编译命令提示符(注意是改造过的那个,而非普通 VS 提示符);
- 执行
set npm_config_arch=arm64; - 照常运行
npm install构建项目。
与交叉编译 x86 模块时的经验一致:如果某些原生模块此前曾为其他架构编译过,可能需要删除 node_modules 强制其重新编译,避免 node-gyp 命中缓存中架构不符的 .obj 产物。该流程与 docs/tutorial/using-native-node-modules.md 中描述的 Electron 原生模块编译规范完全同源——无论是通过 npm_config_target / npm_config_arch / npm_config_disturl 等环境变量驱动 npm 编译,还是用 node-gyp rebuild --target=<版本> --arch=<架构> 手动构建,核心都是让 node-gyp 使用 Electron 的 node 头文件与目标架构工具链完成编译。
调试原生模块
原生模块的调试需要"开发机 + 目标机"两端配合:
- 目标设备端:在 命令提示符 中启动你的应用
.exe,并传入--inspect-brk参数,让进程在加载任何原生模块之前暂停,等待调试器接入。 - 开发机端:启动 Visual Studio 2017。
- 选择 调试 > 附加到进程(Debug > Attach to Process...),输入目标设备的 IP 地址与 Visual Studio 远程调试器(Remote Debugger)显示的端口号。
- 点击 刷新(Refresh),选择要附加的 Electron 进程——具体应附加主进程还是渲染进程,可参考 docs/development/debugging-on-windows.md 中对各进程类型的说明。
- 符号配置:确保应用中原生模块的符号能正确加载。在 VS 2017 中进入 调试 > 选项(Debug > Options...),在 调试 > 符号(Debugging > Symbols)下添加存放
.pdb符号文件的文件夹。 - 附加成功后设置所需断点,并使用 Chrome 面向 Node 的远程调试工具(docs/tutorial/debugging-main-process.md)恢复 JavaScript 执行。
疑难排查与获取帮助
如果你在使用本文档过程中遇到问题,或出现"应用在 x86 下正常、一到 arm64 就失败"的情况,可以在仓库的 docs/development/issues.md 中查看提交规范,并在标题中以 "Windows on Arm" 开头提交 issue,便于维护者快速识别分类。
结合仓库中的同类文档(如 docs/development/build-instructions-gn.md),还可以确认一个通用的排查思路:先用 process.arch / npm_config_arch 双重打印确认目标架构是否正确贯穿到编译与打包脚本;再检查 node-gyp 缓存中 node.lib 的架构与版本;最后核对 MSVC 工具集与链接器是否来自交叉编译命令提示符环境。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00