To mitigate issues around long path names on Windows, slightly speed up require
and conceal your source code from cursory inspection, you can choose to package your app into an asar archive with little changes to your source code.
asar
ArchiveAn asar archive is a simple tar-like format that concatenates files into a single file. Electron can read arbitrary files from it without unpacking the whole file.
Steps to package your app into an asar
archive:
$ npm install -g asar
asar pack
$ asar pack your-app app.asar
asar
ArchivesIn Electron there are two sets of APIs: Node APIs provided by Node.js and Web APIs provided by Chromium. Both APIs support reading files from asar
archives.
With special patches in Electron, Node APIs like fs.readFile
and require
treat asar
archives as virtual directories, and the files in it as normal files in the filesystem.
For example, suppose we have an example.asar
archive under /path/to
:
$ asar list /path/to/example.asar
/app.js
/file.txt
/dir/module.js
/static/index.html
/static/main.css
/static/jquery.min.js
Read a file in the asar
archive:
const fs = require('fs')
fs.readFileSync('/path/to/example.asar/file.txt')
List all files under the root of the archive:
const fs = require('fs')
fs.readdirSync('/path/to/example.asar')
Use a module from the archive:
require('/path/to/example.asar/dir/module.js')
You can also display a web page in an asar
archive with BrowserWindow
:
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('file:///path/to/example.asar/static/index.html')
In a web page, files in an archive can be requested with the file:
protocol. Like the Node API, asar
archives are treated as directories.
For example, to get a file with $.get
:
<script>
let $ = require('./jquery.min.js')
$.get('file:///path/to/example.asar/file.txt', (data) => {
console.log(data)
})
</script>
asar
Archive as a Normal FileFor some cases like verifying the asar
archive’s checksum, we need to read the content of an asar
archive as a file. For this purpose you can use the built-in original-fs
module which provides original fs
APIs without asar
support:
const originalFs = require('original-fs')
originalFs.readFileSync('/path/to/example.asar')
You can also set process.noAsar
to true
to disable the support for asar
in the fs
module:
const fs = require('fs')
process.noAsar = true
fs.readFileSync('/path/to/example.asar')
Even though we tried hard to make asar
archives in the Node API work like directories as much as possible, there are still limitations due to the low-level nature of the Node API.
The archives can not be modified so all Node APIs that can modify files will not work with asar
archives.
Though asar
archives are treated as directories, there are no actual directories in the filesystem, so you can never set the working directory to directories in asar
archives. Passing them as the cwd
option of some APIs will also cause errors.
Most fs
APIs can read a file or get a file’s information from asar
archives without unpacking, but for some APIs that rely on passing the real file path to underlying system calls, Electron will extract the needed file into a temporary file and pass the path of the temporary file to the APIs to make them work. This adds a little overhead for those APIs.
APIs that requires extra unpacking are:
child_process.execFile
child_process.execFileSync
fs.open
fs.openSync
process.dlopen
- Used by require
on native modulesfs.stat
The Stats
object returned by fs.stat
and its friends on files in asar
archives is generated by guessing, because those files do not exist on the filesystem. So you should not trust the Stats
object except for getting file size and checking file type.
asar
ArchiveThere are Node APIs that can execute binaries like child_process.exec
, child_process.spawn
and child_process.execFile
, but only execFile
is supported to execute binaries inside asar
archive.
This is because exec
and spawn
accept command
instead of file
as input, and command
s are executed under shell. There is no reliable way to determine whether a command uses a file in asar archive, and even if we do, we can not be sure whether we can replace the path in command without side effects.
asar
ArchiveAs stated above, some Node APIs will unpack the file to filesystem when calling, apart from the performance issues, it could also lead to false alerts of virus scanners.
To work around this, you can unpack some files creating archives by using the --unpack
option, an example of excluding shared libraries of native modules is:
$ asar pack app app.asar --unpack *.node
After running the command, apart from the app.asar
, there is also an app.asar.unpacked
folder generated which contains the unpacked files, you should copy it together with app.asar
when shipping it to users.