2016-01-28 08:46:28 +00:00
# 應用程式打包
為了減少圍繞著 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 中有兩組 API: Node.js 提供的 Node APIs 和 Chromium 提供的 Web
APIs, 兩組 API 都支援從 `asar` 壓縮檔中讀取檔案。
### Node API
因為 Electron 中有一些特別的補釘,像是 `fs.readFile` 和 `require` 這樣的 Node API 會將 `asar` 壓縮檔視為許多虛擬目錄,將裡頭的檔案視為在檔案系統上的一般檔案。
例如,假設我們有一個 `example.asar` 壓縮檔在 `/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
```
讀取一個在 `asar` 壓縮檔中的檔案:
```javascript
const fs = require('fs');
fs.readFileSync('/path/to/example.asar/file.txt');
```
列出所有在壓縮檔根目錄下的檔案:
```javascript
const fs = require('fs');
fs.readdirSync('/path/to/example.asar');
```
使用一個壓縮檔中的模組:
```javascript
require('/path/to/example.asar/dir/module.js');
```
你也可以利用 `BrowserWindow` 在 `asar` 壓縮檔中呈現一個網頁:
```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
在一個網頁中,壓縮檔中的檔案都可以透過 `file:` 這個協定被存取,如同 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` 壓縮檔檢查碼(checksum)的例子中,我們需要以檔案的方式讀取 `asar` 壓縮檔中的內容,為了達到這個目的,你可以使用內建的
`original-fs` 模組,它提供了沒有 `asar` 支援的原生 `fs` API:
```javascript
var originalFs = require('original-fs');
originalFs.readFileSync('/path/to/example.asar');
```
你也可以設定 `process.noAsar` 為 `true` 來關掉在 `fs` 模組中的 `asar` 支援:
```javascript
process.noAsar = true;
fs.readFileSync('/path/to/example.asar');
```
## Node API 上的限制
儘管我們盡可能的努力嘗試著使 Node API 中的 `asar` 壓縮檔像目錄一樣運作,還是有一些基於 Node API 低階本質的限制存在。
### 壓縮檔都是唯讀的
所有壓縮檔都無法被修改,因此所有可以修改檔案的 Node API 都無法與 `asar ` 壓縮檔一起運作。
### 使用中的目錄無法被設為壓縮檔中的目錄
儘管 `asar` 壓縮檔被視為目錄,卻並沒有真正的目錄在檔案系統中,所以你永遠無法將使用中的目錄設定成 `asar` 壓縮檔中的目錄,把他們以 `cwd` 選項的方式傳遞,對某些 API 也會造成錯誤。
2016-01-28 10:15:44 +00:00
### 更多透過 API 拆封的方法
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
大部分 `fs` API 可以讀取一個檔案,或是不用拆封就從 `asar` 壓縮檔中取得一個檔案的資訊,但對一些需要傳遞真實檔案路徑給現行系統呼叫的 API , Electron 將會解開需要的檔案到一個暫時的檔案,然後傳遞該暫時檔案的路徑給那些 API 以便使他們可以運作,這會增加這些 API 一點負擔。
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
需要額外拆封的 API :
2016-01-28 08:46:28 +00:00
* `child_process.execFile`
* `child_process.execFileSync`
* `fs.open`
* `fs.openSync`
2016-01-28 10:15:44 +00:00
* `process.dlopen` - 在原生模組中被 `require` 使用
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
### `fs.stat` 的不真實的狀態資訊
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
`fs.stat` 回傳的 `Stats` 物件和它在 `asar` 壓縮檔中的檔案朋友都是以猜測的方式產生的,因為那些檔案不存在檔案系統,所以你不應該信任 `Stats` 物件,除了取得檔案大小和確認檔案型態之外。
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
### 執行 `asar` 壓縮檔中的二進位檔
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
有像是 `child_process.exec` 、`child_process.spawn` 和 `child_process.execFile` 的 Node APIs 可以執行二進位檔,但只有 `execFile` 是 `asar` 壓縮檔中可以執行二進位檔的。
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
這是因為 `exec` 和 `spawn` 接受的輸入是 `command` 而不是 `file` ,而 `command` 們都是在 shell 底下執行,我們找不到可靠的方法來決定是否一個命令使用一個在 `asar` 壓縮檔中的檔案,而儘管我們找得到,我們也無法確定是否我們可以在沒有外部影響(side effect)的情況下替換掉命令中的路徑。
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
## 加入拆封檔案到 `asar` 壓縮檔中
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
如前述,一些 Node API 再被呼叫時會拆封檔案到檔案系統,除了效能議題外,它也會導致掃毒軟體發出 false alerts。
2016-01-28 08:46:28 +00:00
2016-01-28 10:15:44 +00:00
要繞過這個問題,你可以透過使用 `--unpack` 選向來拆封一些建立壓縮檔的檔案,以下是一個不包含共享原生模組的函式庫的例子:
2016-01-28 08:46:28 +00:00
```bash
$ asar pack app app.asar --unpack *.node
```
2016-01-28 10:15:44 +00:00
執行這個命令以後,除了 `app.asar` 以外,還有一個帶有拆封檔案的 `app.asar.unpacked` 資料夾被產生出來,當你要發布給使用者時,你應該把它和 `app.asar` 一起複。
2016-01-28 08:46:28 +00:00
[asar]: https://github.com/atom/asar