168 lines
5.7 KiB
Markdown
168 lines
5.7 KiB
Markdown
|
# 應用程式打包
|
|||
|
|
|||
|
為了減少圍繞著 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 也會造成錯誤。
|
|||
|
|
|||
|
### 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 in `asar` Archive
|
|||
|
|
|||
|
As stated above, some Node APIs will unpack the file to filesystem when
|
|||
|
calling, apart from the performance issues, it could also lead to false alerts
|
|||
|
of virus scanners.
|
|||
|
|
|||
|
To work around this, you can unpack some files creating archives by using the
|
|||
|
`--unpack` option, an example of excluding shared libraries of native modules
|
|||
|
is:
|
|||
|
|
|||
|
```bash
|
|||
|
$ asar pack app app.asar --unpack *.node
|
|||
|
```
|
|||
|
|
|||
|
After running the command, apart from the `app.asar`, there is also an
|
|||
|
`app.asar.unpacked` folder generated which contains the unpacked files, you
|
|||
|
should copy it together with `app.asar` when shipping it to users.
|
|||
|
|
|||
|
[asar]: https://github.com/atom/asar
|