进阶 electronjs.org 2026-10-07 23:51:43 · 6 阅读

第5章 Electron 应用中的 ASAR 归档详解

# ASAR 归档 创建应用分发后,应用的源代码通常会打包进一个 ASAR 归档,这是专为 Electron 设计的一种简单、可扩展的归档格式。打包应用可以缓解 Windows 上路径过长的问题,加快 require 速度,还能防止源代码被随意查看。 打包后的应用运行在虚拟文件系统中,大多数 API 都能正常工作。但因为有少数注意事项,某些情况下你可能需要显式地操作 ASAR 归档。 ## 使用 ASAR 归档 Electron 中有两套 API:Node.js 提供的 Node API 和 Chromium 提供的 Web API,两者都支持从 ASAR 归档中读取文件。 ### Node API Electron 对 Node API 做了特殊补丁,使 fs.readFile 和 require 等方法把 ASAR 归档当作虚拟目录处理,归档内的文件则像文件系统中的普通文件一样。 例如,假设在 /path/to 下有一个 example.asar 归档: $ asar list /path/to/example.asar
/app.js
/file.txt
/dir/module.js
/static/index.html
/static/main.css
/static/jquery.min.js
读取归档中的文件: const fs = require('node:fs')

fs.readFileSync('/path/to/example.asar/file.txt')
列出归档根目录下的所有文件: const fs = require('node:fs')

fs.readdirSync('/path/to/example.asar')
使用归档中的模块: require('./path/to/example.asar/dir/module.js')
你也可以用 BrowserWindow 展示归档中的网页: const { BrowserWindow } = require('electron')

const win = new BrowserWindow()

win.loadURL('file:///path/to/example.asar/static/index.html')
### Web API 在网页中,可以通过 file: 协议请求归档内的文件。与 Node API 一样,ASAR 归档会被当作目录处理。 例如,用 $.get 获取文件:
## 将 ASAR 归档当作普通文件处理 某些场景下(比如校验 ASAR 归档的校验和),我们需要把归档当作普通文件来读取其内容。这时可以使用内置的 original-fs 模块,它提供不带 asar 支持的原始 fs API: const originalFs = require('original-fs')

originalFs.readFileSync('/path/to/example.asar')
也可以将 process.noAsar 设为 true,来禁用 fs 模块的 asar 支持: const fs = require('node:fs')

process.noAsar = true
fs.readFileSync('/path/to/example.asar')

Node API 的局限性

尽管我们尽力让 Node API 中的 ASAR 存档行为尽可能接近普通目录,但受限于 Node API 底层特性,仍存在一些限制。

存档只读

存档本身不可修改,因此所有涉及文件修改操作的 Node API 在 ASAR 存档上均无法工作。

无法将工作目录设置为存档内的目录

虽然 ASAR 存档被当作目录处理,但文件系统层并没有真实的目录结构,因此无法将工作目录设置为 ASAR 内部的目录。若通过 cwd 参数将存档内路径传入某些 API,会直接报错。

部分 API 需要额外解包

大多数 fs API 可以直接从 ASAR 存档中读取文件或获取文件信息,无需解包。但依赖真实文件路径来调用底层系统调用的 API 是个例外:此时 Electron 会将所需文件提取到临时文件中,再将该临时文件路径传给 API 以确保其正常运行。这会为这类 API 带来少量额外开销。

需要额外解包的 API 包括:

  • child_process.execFile
  • child_process.execFileSync
  • fs.open
  • fs.openSync
  • process.dlopen(require 加载原生模块时用到)

fs.stat 返回的伪 Stat 信息

对 ASAR 存档内的文件调用 fs.stat 及其相关方法时,返回的 Stats 对象其实是估算出来的,因为文件并不真实存在于文件系统中。因此,除了文件大小和文件类型,其他 Stats 字段都不应信任。

执行 ASAR 存档内的二进制文件

有一些 Node API 可以执行二进制文件,如 child_process.exec、child_process.spawn 和 child_process.execFile,但只有 execFile 支持直接执行 ASAR 存档内的二进制文件。

原因在于 exec 和 spawn 接受的是命令字符串而非文件路径,且命令在 shell 下执行。我们无法可靠地判断命令中是否引用了 ASAR 内的文件,即便判断出来,替换命令中的路径也可能产生不可预知的副作用。

为 ASAR 存档添加未打包文件

如上所述,某些 Node API 被调用时会把文件解包到文件系统中。除了性能损耗,这种行为还可能触发各类杀毒软件扫描。作为变通方案,可以使用 --unpack 选项将特定文件保留为未打包状态。以下示例中,原生 Node.js 模块的共享库将不会被打包进 ASAR:

$ asar pack app app.asar --unpack *.node

执行该命令后,你会发现在生成 app.asar 文件的同时,还创建了一个名为 app.asar.unpacked 的文件夹。它存放着未打包的文件,需要和 app.asar 归档一起分发。

评论 (0)