184 lines
5.5 KiB
Markdown
184 lines
5.5 KiB
Markdown
# Application Packaging
|
|
|
|
To mitigate [issues](https://github.com/joyent/node/issues/6960) 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][asar]
|
|
archive with little changes to your source code.
|
|
|
|
## Generating `asar` Archive
|
|
|
|
An [asar][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:
|
|
|
|
### 1. Install the asar Utility
|
|
|
|
```bash
|
|
$ npm install -g asar
|
|
```
|
|
|
|
### 2. Package with `asar pack`
|
|
|
|
```bash
|
|
$ asar pack your-app app.asar
|
|
```
|
|
|
|
## Using `asar` Archives
|
|
|
|
In 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.
|
|
|
|
### Node API
|
|
|
|
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`:
|
|
|
|
```bash
|
|
$ 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:
|
|
|
|
```javascript
|
|
const fs = require('fs');
|
|
fs.readFileSync('/path/to/example.asar/file.txt');
|
|
```
|
|
|
|
List all files under the root of the archive:
|
|
|
|
```javascript
|
|
const fs = require('fs');
|
|
fs.readdirSync('/path/to/example.asar');
|
|
```
|
|
|
|
Use a module from the archive:
|
|
|
|
```javascript
|
|
require('/path/to/example.asar/dir/module.js');
|
|
```
|
|
|
|
You can also display a web page in an `asar` archive with `BrowserWindow`:
|
|
|
|
```javascript
|
|
const { BrowserWindow } = require('electron');
|
|
let win = new BrowserWindow({width: 800, height: 600});
|
|
win.loadURL('file:///path/to/example.asar/static/index.html');
|
|
```
|
|
|
|
### Web API
|
|
|
|
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`:
|
|
|
|
```html
|
|
<script>
|
|
var $ = require('./jquery.min.js');
|
|
$.get('file:///path/to/example.asar/file.txt', (data) => {
|
|
console.log(data);
|
|
});
|
|
</script>
|
|
```
|
|
|
|
### Treating an `asar` Archive as a Normal File
|
|
|
|
For some cases like verifying the `asar` archive's checksum, we need to read the
|
|
content of `asar` archive as file. For this purpose you can use the built-in
|
|
`original-fs` module which provides original `fs` APIs without `asar` support:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
process.noAsar = true;
|
|
fs.readFileSync('/path/to/example.asar');
|
|
```
|
|
|
|
## Limitations on Node API
|
|
|
|
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.
|
|
|
|
### Archives Are Read-only
|
|
|
|
The archives can not be modified so all Node APIs that can modify files will not
|
|
work with `asar` archives.
|
|
|
|
### Working Directory Can Not Be Set to Directories in Archive
|
|
|
|
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.
|
|
|
|
### Extra Unpacking on Some APIs
|
|
|
|
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 modules
|
|
|
|
### Fake Stat Information of `fs.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.
|
|
|
|
### Executing Binaries Inside `asar` Archive
|
|
|
|
There 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.
|
|
|
|
## Adding Unpacked Files in `asar` Archive
|
|
|
|
As 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:
|
|
|
|
```bash
|
|
$ 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.
|
|
|
|
[asar]: https://github.com/atom/asar
|