# 應用打包
為舒緩 Windows 下路徑名過長的問題[issues](https://github.com/joyent/node/issues/6960),
也略對 `require` 加速以及簡單隱匿你的源代碼,你可以通過極小的源代碼改動將你的應用打包成 [asar][asar]。
## 生成 `asar` 包
[asar][asar] 是一種將多個文件合并成一個文件的類 tar 風格的歸檔格式。
Electron 可以無需解壓,即從其中讀取任意文件內容。
參照如下步驟將你的應用打包成 `asar`:
### 1. 安裝 asar
```bash
$ npm install -g asar
```
### 2. 用 `asar pack` 打包
```bash
$ asar pack your-app app.asar
```
## 使用 `asar` 包
在 Electron 中有兩類 APIs:Node.js 提供的 Node API 和 Chromium 提供的 Web API。
這兩種 API 都支持從 `asar` 包中讀取文件。
### Node API
由于 Electron 中打了特別補丁, Node API 中如 `fs.readFile` 或者 `require` 之類
的方法可以將 `asar` 視之為虛擬文件夾,讀取 `asar` 里面的文件就和從真實的文件系統中讀取一樣。
例如,假設我們在 `/path/to` 文件夾下有個 `example.asar` 包:
```bash
$ asar list /path/to/example.asar
/app.js
/file.txt
/dir/module.js
/static/index.html
/static/main.css
/static/jquery.min.js
```
從 `asar` 包讀取一個文件:
```javascript
const fs = require('fs');
fs.readFileSync('/path/to/example.asar/file.txt');
```
列出 `asar` 包中根目錄下的所有文件:
```javascript
const fs = require('fs');
fs.readdirSync('/path/to/example.asar');
```
使用 `asar` 包中的一個模塊:
```javascript
require('/path/to/example.asar/dir/module.js');
```
你也可以使用 `BrowserWindow` 來顯示一個 `asar` 包里的 web 頁面:
```javascript
const BrowserWindow = require('electron').BrowserWindow;
var win = new BrowserWindow({width: 800, height: 600});
win.loadURL('file:///path/to/example.asar/static/index.html');
```
### Web API
在 Web 頁面里,用 `file:` 協議可以獲取 `asar` 包中文件。和 Node API 一樣,視 `asar` 包如虛擬文件夾。
例如,用 `$.get` 獲取文件:
```html
<script>
var $ = require('./jquery.min.js');
$.get('file:///path/to/example.asar/file.txt', function(data) {
console.log(data);
});
</script>
```
### 像“文件”那樣處理 `asar` 包
有些場景,如:核查 `asar` 包的校驗和,我們需要像讀取“文件”那樣讀取 `asar` 包的內容(而不是當成虛擬文件夾)。
你可以使用內置的 `original-fs` (提供和 `fs` 一樣的 API)模塊來讀取 `asar` 包的真實信息。
```javascript
var originalFs = require('original-fs');
originalFs.readFileSync('/path/to/example.asar');
```
## Node API 缺陷
盡管我們已經盡了最大努力使得 `asar` 包在 Node API 下的應用盡可能的趨向于真實的目錄結構,但仍有一些底層 Node API 我們無法保證其正常工作。
### `asar` 包是只讀的
`asar` 包中的內容不可更改,所以 Node APIs 里那些可以用來修改文件的方法在對待 `asar` 包時都無法正常工作。
### Working Directory 在 `asar` 包中無效
盡管 `asar` 包是虛擬文件夾,但其實并沒有真實的目錄架構對應在文件系統里,所以你不可能將 working Directory
設置成 `asar` 包里的一個文件夾。將 `asar` 中的文件夾以 `cwd` 形式作為參數傳入一些 API 中也會報錯。
### API 中的額外“開箱”
大部分 `fs` API 可以無需解壓即從 `asar` 包中讀取文件或者文件的信息,但是在處理一些依賴真實文件路徑的底層
系統方法時,Electron 會將所需文件解壓到臨時目錄下,然后將臨時目錄下的真實文件路徑傳給底層系統方法使其正
常工作。 對于這類API,耗費會略多一些。
以下是一些需要額外解壓的 API:
* `child_process.execFile`
* `child_process.execFileSync`
* `fs.open`
* `fs.openSync`
* `process.dlopen` - `require`native模塊時用到
### `fs.stat` 獲取的 stat 信息不可靠
對 `asar` 包中的文件取 `fs.stat`,返回的 `Stats` 對象不是精確值,因為這些文件不是真實存在于文件系
統里。所以除了文件大小和文件類型以外,你不應該依賴 `Stats` 對象的值。
### 執行 `asar` 包中的程序
Node 中有一些可以執行程序的 API,如 `child_process.exec`,`child_process.spawn` 和 `child_process.execFile` 等,
但只有 `execFile` 可以執行 `asar` 包中的程序。
因為 `exec` 和 `spawn` 允許 `command` 替代 `file` 作為輸入,而 `command` 是需要在 shell 下執行的,目前沒有
可靠的方法來判斷 `command` 中是否在操作一個 `asar` 包中的文件,而且即便可以判斷,我們依舊無法保證可以在無任何
副作用的情況下替換 `command` 中的文件路徑。
## 打包時排除文件
如上所述,一些 Node API 會在調用時將文件解壓到文件系統中,除了效率問題外,也有可能引起殺毒軟件的注意!
為解決這個問題,你可以在生成 `asar` 包時使用 `--unpack` 選項來排除一些文件,使其不打包到 `asar` 包中,
下面是如何排除一些用作共享用途的 native 模塊的方法:
```bash
$ asar pack app app.asar --unpack *.node
```
經過上述命令后,除了生成的 `app.asar` 包以外,還有一個包含了排除文件的 `app.asar.unpacked` 文件夾,
你需要將這個文件夾一起拷貝,提供給用戶。
[asar]: https://github.com/atom/asar
- 介紹
- 常見問題
- Electron 常見問題
- 向導
- 支持平臺
- 分發應用
- 提交應用到 Mac App Store
- 打包應用
- 使用 Node 原生模塊
- 主進程調試
- 使用 Selenium 和 WebDriver
- 使用開發人員工具擴展
- 使用 Pepper Flash 插件
- 使用 Widevine CDM 插件
- 教程
- 快速入門
- 桌面環境集成
- 在線/離線事件探測
- API文檔
- 簡介
- 進程對象
- 支持的 Chrome 命令行開關
- 環境變量
- 自定義的 DOM 元素
- File 對象
- &lt;webview&gt; 標簽
- window.open 函數
- 在主進程內可用的模塊
- app
- autoUpdater
- BrowserWindow
- contentTracing
- dialog
- globalShortcut
- ipcMain
- Menu
- MenuItem
- powerMonitor
- powerSaveBlocker
- protocol
- session
- webContents
- Tray
- 在渲染進程(網頁)內可用的模塊
- desktopCapturer
- ipcRenderer
- remote
- webFrame
- 在兩種進程中都可用的模塊
- clipboard
- crashReporter
- nativeImage
- screen
- shell
- 開發
- 代碼規范
- 源碼目錄結構
- 與 NW.js(原 node-webkit)在技術上的差異
- 構建系統概覽
- 構建步驟(OS X)
- 構建步驟(Windows)
- 構建步驟(Linux)
- 在調試中使用 Symbol Server