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
归档一起发布。