electron/docs/tutorial/application-packaging.md

195 lines
6 KiB
Markdown
Raw Normal View History

2015-09-01 02:12:33 +00:00
# Application Packaging
2014-09-29 15:05:02 +00:00
2015-09-01 02:12:33 +00:00
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.
2014-09-29 15:05:02 +00:00
2018-02-19 23:50:38 +00:00
Most users will get this feature for free, since it's supported out of the box
by [`electron-packager`][electron-packager], [`electron-forge`][electron-forge],
and [`electron-builder`][electron-builder]. If you are not using any of these
tools, read on.
## Generating `asar` Archives
2014-09-29 15:05:02 +00:00
An [asar][asar] archive is a simple tar-like format that concatenates files
2015-09-01 02:12:33 +00:00
into a single file. Electron can read arbitrary files from it without unpacking
2014-09-29 15:05:02 +00:00
the whole file.
2015-09-01 02:12:33 +00:00
Steps to package your app into an `asar` archive:
2014-09-29 15:05:02 +00:00
2015-09-01 02:12:33 +00:00
### 1. Install the asar Utility
2014-09-29 15:05:02 +00:00
2017-11-24 10:13:57 +00:00
```sh
2014-09-29 15:05:02 +00:00
$ npm install -g asar
```
### 2. Package with `asar pack`
2017-11-24 10:13:57 +00:00
```sh
2014-09-29 15:05:02 +00:00
$ asar pack your-app app.asar
```
2015-09-01 02:12:33 +00:00
## Using `asar` Archives
2014-09-29 15:05:02 +00:00
2015-09-01 02:12:33 +00:00
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.
2014-09-29 15:05:02 +00:00
### Node API
2015-04-16 03:31:12 +00:00
With special patches in Electron, Node APIs like `fs.readFile` and `require`
2014-09-29 15:05:02 +00:00
treat `asar` archives as virtual directories, and the files in it as normal
files in the filesystem.
2014-09-29 15:05:02 +00:00
For example, suppose we have an `example.asar` archive under `/path/to`:
2017-11-24 10:13:57 +00:00
```sh
2014-09-29 15:05:02 +00:00
$ 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:
2014-09-29 15:05:02 +00:00
```javascript
const fs = require('fs')
fs.readFileSync('/path/to/example.asar/file.txt')
2014-09-29 15:05:02 +00:00
```
List all files under the root of the archive:
2014-09-29 15:05:02 +00:00
```javascript
const fs = require('fs')
fs.readdirSync('/path/to/example.asar')
2014-09-29 15:05:02 +00:00
```
Use a module from the archive:
```javascript
2020-07-09 17:18:49 +00:00
require('./path/to/example.asar/dir/module.js')
2014-09-29 15:05:02 +00:00
```
You can also display a web page in an `asar` archive with `BrowserWindow`:
```javascript
2018-02-19 23:50:38 +00:00
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.loadURL('file:///path/to/example.asar/static/index.html')
```
2014-09-29 15:05:02 +00:00
### Web API
2015-09-01 02:12:33 +00:00
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.
2014-09-29 15:05:02 +00:00
For example, to get a file with `$.get`:
```html
<script>
let $ = require('./jquery.min.js')
$.get('file:///path/to/example.asar/file.txt', (data) => {
console.log(data)
})
2014-09-29 15:05:02 +00:00
</script>
```
2015-09-01 02:12:33 +00:00
### Treating an `asar` Archive as a Normal File
2014-11-12 03:58:03 +00:00
For some cases like verifying the `asar` archive's checksum, we need to read the
2016-07-22 21:52:43 +00:00
content of an `asar` archive as a file. For this purpose you can use the built-in
2014-11-12 03:58:03 +00:00
`original-fs` module which provides original `fs` APIs without `asar` support:
```javascript
const originalFs = require('original-fs')
originalFs.readFileSync('/path/to/example.asar')
2014-11-12 03:58:03 +00:00
```
2015-12-01 05:43:52 +00:00
You can also set `process.noAsar` to `true` to disable the support for `asar` in
the `fs` module:
```javascript
const fs = require('fs')
process.noAsar = true
fs.readFileSync('/path/to/example.asar')
2015-12-01 05:43:52 +00:00
```
2016-07-22 21:52:43 +00:00
## Limitations of the Node API
2014-09-29 15:05:02 +00:00
Even though we tried hard to make `asar` archives in the Node API work like
2014-09-29 15:05:02 +00:00
directories as much as possible, there are still limitations due to the
low-level nature of the Node API.
2014-09-29 15:05:02 +00:00
2015-09-01 02:12:33 +00:00
### Archives Are Read-only
2014-09-29 15:05:02 +00:00
The archives can not be modified so all Node APIs that can modify files will not
2014-09-29 15:05:02 +00:00
work with `asar` archives.
2015-09-01 02:12:33 +00:00
### Working Directory Can Not Be Set to Directories in Archive
2014-09-29 15:05:02 +00:00
Though `asar` archives are treated as directories, there are no actual
directories in the filesystem, so you can never set the working directory to
2015-09-01 02:12:33 +00:00
directories in `asar` archives. Passing them as the `cwd` option of some APIs
will also cause errors.
2014-09-29 15:05:02 +00:00
2015-09-01 02:12:33 +00:00
### Extra Unpacking on Some APIs
2014-09-29 15:05:02 +00:00
2015-09-01 02:12:33 +00:00
Most `fs` APIs can read a file or get a file's information from `asar` archives
2014-09-29 15:05:02 +00:00
without unpacking, but for some APIs that rely on passing the real file path to
2015-04-16 03:31:12 +00:00
underlying system calls, Electron will extract the needed file into a
2014-09-29 15:05:02 +00:00
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`
2015-11-27 13:29:31 +00:00
* `child_process.execFileSync`
2014-09-29 15:05:02 +00:00
* `fs.open`
* `fs.openSync`
* `process.dlopen` - Used by `require` on native modules
2015-09-01 02:12:33 +00:00
### Fake Stat Information of `fs.stat`
2014-09-29 15:05:02 +00:00
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
2014-09-29 15:05:02 +00:00
filesystem. So you should not trust the `Stats` object except for getting file
size and checking file type.
2015-11-27 13:29:31 +00:00
### 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.
2018-02-19 23:50:38 +00:00
## Adding Unpacked Files to `asar` Archives
2018-02-19 23:50:38 +00:00
As stated above, some Node APIs will unpack the file to the filesystem when
called. Apart from the performance issues, various anti-virus scanners might
be triggered by this behavior.
2018-02-19 23:50:38 +00:00
As a workaround, you can leave various files unpacked using the `--unpack` option.
In the following example, shared libraries of native Node.js modules will not be
2018-02-19 23:50:38 +00:00
packed:
2017-11-24 10:13:57 +00:00
```sh
$ asar pack app app.asar --unpack *.node
```
2018-02-19 23:50:38 +00:00
After running the command, you will notice that a folder named `app.asar.unpacked`
was created together with the `app.asar` file. It contains the unpacked files
and should be shipped together with the `app.asar` archive.
2015-03-20 13:32:10 +00:00
2016-05-06 17:09:24 +00:00
[asar]: https://github.com/electron/asar
[electron-packager]: https://github.com/electron/electron-packager
2018-02-19 23:50:38 +00:00
[electron-forge]: https://github.com/electron-userland/electron-forge
[electron-builder]: https://github.com/electron-userland/electron-builder