# Application packaging

To protect your app's resources and source code from the users, 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, atom-shell can read arbitrary file in it without unpacking
the whole file.

Following is the 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 atom-shell 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 atom-shell, 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
var fs = require('fs');
fs.readFileSync('/path/to/example.asar/file.txt');
```

List all files under the root of the archive:

```javascript
var fs = require('fs');
fs.readdirSync('/path/to/example.asar');
```

Use a module from the archive:

```javascript
require('/path/to/example.asar/dir/module.js');
```

### Web API

In a web page, files in archive can be requested by using the `asar:` 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('asar:/path/to/example.asar/file.txt', function(data) {
  console.log(data);
});
</script>
```

The `asar:` protocol can also be used to request normal files in filesystem,
just like the `file:` protocol. But unlike `file:` protocol, there are no
slashes (`//`) after `asar:`.

You can also display a web page in an `asar` archive with `BrowserWindow`:

```javascript
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({width: 800, height: 600});
win.loadUrl('asar:/path/to/example.asar/static/index.html');
```

## 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 to `cwd` option of some APIs will
also cause errors.

### Extra unpacking on some APIs

Most `fs` APIs can read file or get file's information from `asar` archives
without unpacking, but for some APIs that rely on passing the real file path to
underlying system calls, atom-shell 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.fork`
* `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.

[asar]: https://github.com/atom/asar