ASAR 档案
创建应用程序分发后,应用程序的源代码通常会捆绑到 ASAR 档案中,这是一种为 Electron 应用程序设计的简单可扩展存档格式。通过捆绑应用程序,我们可以缓解 Windows 上长路径名的问题,加快 require
的速度,并隐藏源代码,使其不易被粗略查看。
捆绑的应用程序在虚拟文件系统中运行,大多数 API 都可以正常工作,但在某些情况下,由于一些注意事项,您可能需要明确地处理 ASAR 档案。
使用 ASAR 档案
在 Electron 中,有两套 API:Node.js 提供的 Node API 和 Chromium 提供的 Web API。这两套 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
读取 ASAR 档案中的文件
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
显示 ASAR 档案中的网页
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
获取文件
<script>
let $ = require('./jquery.min.js')
$.get('file:///path/to/example.asar/file.txt', (data) => {
console.log(data)
})
</script>
将 ASAR 档案视为普通文件
在某些情况下,例如验证 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 档案中的目录。将它们作为某些 API 的 cwd
选项传递也会导致错误。
某些 API 需要额外解包
大多数 fs
API 都可以从 ASAR 档案中读取文件或获取文件信息而无需解包,但对于某些依赖于将实际文件路径传递给底层系统调用的 API,Electron 会将所需文件提取到一个临时文件中,并将临时文件的路径传递给 API,使其能够工作。这会给这些 API 增加一些开销。
需要额外解包的 API 包括
child_process.execFile
child_process.execFileSync
fs.open
fs.openSync
process.dlopen
- 用于require
原生模块
fs.stat
的伪造统计信息
fs.stat
及其相关函数在 asar
档案中的文件上返回的 Stats
对象是通过猜测生成的,因为这些文件在文件系统上不存在。因此,除了获取文件大小和检查文件类型外,您不应信任 Stats
对象。
在 ASAR 档案内执行二进制文件
有一些 Node API 可以执行二进制文件,例如 child_process.exec
、child_process.spawn
和 child_process.execFile
,但只有 execFile
支持在 ASAR 档案内执行二进制文件。
这是因为 exec
和 spawn
接受 command
作为输入而不是 file
,并且 command
在 shell 下执行。没有可靠的方法可以确定命令是否使用了 asar 档案中的文件,即使我们确定了,也无法确定是否可以在不产生副作用的情况下替换命令中的路径。
向 ASAR 档案添加未打包文件
如上所述,某些 Node API 在被调用时会将文件解包到文件系统中。除了性能问题外,各种杀毒软件可能会被此行为触发。
作为一种解决方法,您可以使用 --unpack
选项保留各种文件不打包。在以下示例中,原生 Node.js 模块的共享库将不被打包
$ asar pack app app.asar --unpack *.node
运行命令后,您会注意到与 app.asar
文件一起创建了一个名为 app.asar.unpacked
的文件夹。它包含未打包的文件,应与 app.asar
档案一起分发。