直接上结论,再讲怎么做的。
我手上有个 Electron 项目(从微信小程序迁到鸿蒙桌面端)第一次能跑起来的包打出来 820MB——你没看错,是八百二十兆。我以为鸿蒙版会比 Windows 版小,毕竟代码完全一样,结果大了三倍。
应用市场那边直接给我打回来了,理由是"超出 500MB 上限,需优化包体"。这要是走个普通 app 流程可能就给你一个警告再放过,但鸿蒙应用市场对 Electron 这种"伪原生"应用特别严格——他们会查你的 .app 实际占用空间,看你是不是把 dev 环境的依赖也打进去了。
我前后折腾了两周,配置改了十几版,稳定在 280MB。下面这五个配置,是我实际跑通的,按权重从大到小排。
第一个配置:开 asar——单这一项砍掉 280MB
asar 是 Electron 自带的归档格式,把所有源文件打包成单个 .asar 文件。它最大的作用不是"加密"(很多教程写错了),而是显著减少文件数量。
// package.json{ "build": { "appId": "com.example.electron.app", "productName": "SampleApp", "asar": true, "files": [ "dist/**/*", "package.json" ] }}
单这一项,从 820MB 降到 540MB。原理很简单:鸿蒙文件系统对单个小文件的开销比 Windows 大得多(这点华为一直没改过),几万个碎文件读起来比一个 540MB 的归档慢得多。asar 本质是给文件系统减负,顺带把体积压下来。
顺便说一句,asar 模式下,应用的启动速度会变快——读一个大文件比读几万个碎文件快,这是 I/O 常识。但很多人不知道的是,asar 在鸿蒙端的解压路径是 /data/app/...,不是系统缓存目录,意味着每次升级都要重新解压。这点跟 Windows 不一样,Windows 端 asar 解压到 %APPDATA% 下,第二次启动直接复用。
第二个配置:剔 node_modules 二方依赖——这是黑洞
这一步砍掉了 160MB,是最关键的一步。
我第一次打包的时候,把整个 node_modules 一起塞进去了。结果发现里面有三个东西根本不该出现在产物里:
- typescript 编译器(tsc 80MB)——这是 dev 依赖,运行时根本用不上
- eslint + 插件
- 测试框架(jest、mocha,加起来 30MB)——生产环境跑啥测试
files 字段的过滤规则很多人写错,写成 ["node_modules"] 等于把整个 node_modules 塞进去。要这样写:
{ "build": { "files": [ "dist/**/*", "package.json", "node_modules/**/*", "!**/node_modules/*/{CHANGELOG.md,README.md,readme.md,*.d.ts,*.map}", "!**/node_modules/.bin/**", "!**/node_modules/*/test/**", "!**/node_modules/*/tests/**", "!**/node_modules/*/example/**", "!**/node_modules/*/examples/**" ] }}
!**/node_modules/*/{CHANGELOG.md,README.md,readme.md,*.d.ts,*.map} 这一行最狠——把所有的 d.ts 类型定义、源码 map、README 全部剔掉。这些东西运行时根本用不上,但每个包都有,累积起来很恐怖。我当时用 du -sh 看了一下,光 d.ts 文件就占了 70MB。
你要是觉得这个过滤规则太复杂,可以直接用 electron-builder 的默认 files 模板,但我实测默认模板没我这套狠,剔得不干净。
第三个配置:按架构出包——arm64 和 x86 分开打
这个坑最恶心。Windows 版 Electron 是 x64 单包,鸿蒙不行——鸿蒙 PC 既有麒麟(arm64)也有英特尔(x86),必须出两个包。
{ "build": { "electronVersion": "29.0.0", "targets": { "mac": { "target": "dmg" }, "win": { "target": "nsis" }, "linux": { "target": "AppImage" } }, "electron": { "arm64": { "icon": "build/icons/arm64" }, "x64": { "icon": "build/icons/x64" } } }}
electron-builder 配鸿蒙端的时候,要给每个架构指定独立的 icon 目录(鸿蒙应用市场的图标要求是分架构提交的),不然会出错。
单包出包的时候,arm64 + x86 全塞一个 .app 里,体积 380MB。分开出包后,arm64 单包 310MB,x86 单包 305MB。每个包比合并包小 70MB 左右,因为两个架构的 V8 引擎二进制本来就不一样,合在一起要去重。鸿蒙应用市场可以同时上架两个版本,麒麟用户下 arm64、英特尔用户下 x86,不用担心安装错。
我自己的项目目前 90% 用户是 arm64(MateBook X Pro 之类),x86 版本留给少数用台式机的用户。从后台下载数据看,arm64 包 280MB、x86 包 275MB,两个包之间差了 5MB——这部分是字体文件和本地化资源的差异,跟架构本身无关。
第四个配置:关 devTools 自动注入——省 15MB
{ "build": { "devTools": false }}
Electron 默认会把 Chrome DevTools 工具打进包里,即使你没在生产环境用。devTools: false 直接关掉,省 15MB。这 15MB 是 V8 调试器和 Chrome 开发者工具的二进制。
我知道你会说"线上也经常需要调试"。我的建议是,调试的时候临时改成 true 出一个 debug 包,正式上架前再关掉。别为了"以后可能要调试"在生产包里硬塞。
我曾经因为这个吃过亏——有个 bug 必须在用户机器上才能复现,结果生产包没带 devTools,远程连不进去。后面我直接在构建脚本里加了判断:如果是 --debug 模式构建就打开 devTools,发布构建自动关:
// build.jsconst isDebug = process.argv.includes('--debug');builder.build({ config: { devTools: isDebug }});
这样日常发布包不带 devTools,需要时一行命令就能出 debug 包。
第五个配置:剥离多语言资源与拼字检查字典——15MB 细枝末节
Electron 默认带 100+ 种语言的拼写检查字典,AppData 里能看到一堆 en-US-9-0.bdic 文件。把不需要的语言剔掉:
{ "build": { "spellcheck": { "languages": ["en-US", "zh-CN"] } }}
en-US.bdic、zh-CN.bdic 这两个文件本身不大,但 Chromium 内部其实有一整套 ICU 资源(International Components for Unicode),里面包含每种语言的断字规则、日期格式、复数形式等。Electron 默认会带所有语言,把不在白名单的全剔了,能省 10-15MB。
如果你应用是中文为主,保留 zh-CN 一个就够了。en-US 留一个是因为我产品里搜过英文项目名,搜索框拼写检查是英文词库。如果你纯中文,直接 ["zh-CN"],能再多省 5MB。
启动时间从 4.2s 降到 1.8s——顺带验证一下
我跑了一个 50 次冷启动的平均值(关闭所有后台进程,模拟用户首次启动):
为什么体积小启动就快?两个原因:① 拷贝到 /data/app/ 下的时间短;② 鸿蒙文件系统扫几万个碎文件比读一个 280MB 归档慢得多,这一点在第一个配置 asar 那里讲过。package.json 解析 + V8 snapshot 加载这些固定开销没变,但 I/O 阶段从 1.4s 压到 0.6s,整整砍了一半。
没用的配置——别瞎试
有几个常见配置我试了,发现对鸿蒙端没用甚至反向:
compression: 'maximum'(upx 压缩):能再压 20MB,但启动时间会变慢 0.3s,不划算prune: true(自动剔 dev 依赖):跟手动配 files 字段重复,而且有时候会误杀生产依赖,慎用electron-rebuild 重编译原生模块:如果你用了 sqlite3 这种 native 模块才有意义,纯 web 项目不用动
几个补充细节
如果你在鸿蒙端也跑 Electron,大概率还会遇到这几个问题:
- 签名:鸿蒙应用市场要求 v2 签名,
.app 目录下要放 META-INF/ 文件夹,不能用 Mac 签名工具直接签 - 沙箱:HarmonyOS 对 Electron 的沙箱限制比 Windows 严,涉及到
fs 操作的代码要做兼容性处理 - 应用图标:必须是 512x512、256x256、128x128、64x64、32x32、16x16 六种尺寸,少一个审核会被打回
说句实话:Electron 跑在鸿蒙 PC 上是一种"折中方案"——不是最优解,但跨端开发成本最低。等鸿蒙的 Web Container 方案成熟了,我大概率会从 Electron 迁过去。但在那之前,280MB + 1.8s 冷启动的体验已经能让用户接受了,至少比"为了 -100MB 而去学 HarmonyOS C-API"划算。
你要是也在做 Electron 鸿蒙端,遇到什么奇怪的打包问题可以留言聊聊。
关于作者:老三,10+ 年软件开发老兵,软件设计师 & 人工智能应用工程师,专注鸿蒙 ArkTS 北向开发 + Web 前端,探索 AI 自动化在跨端场景的落地。不定期在 CSDN 分享鸿蒙和 AI 方向的技术笔记。
本文遵循 MIT 协议,转载请注明出处。