# 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. 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 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 ```sh $ npm install -g asar ``` ### 2. Package with `asar pack` ```sh $ 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`: ```sh $ 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') const win = new BrowserWindow() 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 ``` ### 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 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: ```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 const fs = require('fs') process.noAsar = true fs.readFileSync('/path/to/example.asar') ``` ## Limitations of the 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 to `asar` Archives 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. 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 packed: ```sh $ asar pack app app.asar --unpack *.node ``` 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. [asar]: https://github.com/electron/asar [electron-packager]: https://github.com/electron-userland/electron-packager [electron-forge]: https://github.com/electron-userland/electron-forge [electron-builder]: https://github.com/electron-userland/electron-builder