アプリケーションのパッケージ化

Windows上の長いパス名周りの問題 を軽減したり、requireを若干スピードアップしたり、簡単な調査からソースコードを隠したりするために、ソースコードを少々変更して、アプリケーションを asar アーカイブとしてパッケージ化することもできます。

asar アーカイブの生成

asar アーカイブは、1つのファイルに連結されたtarライクのシンプルなフォーマットです。Electron はファイル全体をアンパックしなくても任意のファイルを読み込めます。

アプリを asar アーカイブにパッケージ化する手順:

1. asar ユーティリティのインストール

$ npm install -g asar

2. asar packでパッケージ化する

$ asar pack your-app app.asar

asar アーカイブを使用する

Electronには、2組のAPIがあります。Node.js により提供される Node API、そして Chromium により提供される Web API です。どちらの API も asar アーカイブからのファイル読み込みに対応しています。

Node API

Electronでは特定のパッチで、fs.readFilerequire のようなNode APIは、asar アーカイブを仮想ディレクトリのように扱い、ファイルをファイルシステム上の通常のファイルのように扱います。

例えば、/path/to 配下に、example.asar アーカイブがあると仮定します:

$ asar list /path/to/example.asar
/app.js
/file.txt
/dir/module.js
/static/index.html
/static/main.css
/static/jquery.min.js

asar アーカイブ内のファイルを読み込む:

const fs = require('fs');
fs.readFileSync('/path/to/example.asar/file.txt');

アーカイブのルート直下にあるすべてのファイルを一覧にする:

const fs = require('fs');
fs.readdirSync('/path/to/example.asar');

アーカイブからモジュールを使用する:

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

BrowserWindow を使って asar アーカイブ内の Web ページを表示することもできます:

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: プロトコルでリクエストできます。 Node API と同様、asar アーカイブはディレクトリのように扱われます。

例えば、 $.get でファイルを取得できます:

<script>
var $ = require('./jquery.min.js');
$.get('file:///path/to/example.asar/file.txt', function(data) {
  console.log(data);
});
</script>

asar アーカイブを通常のファイルのように扱う

アーカイブのチェックサムを検証する等の幾つかのケースでは、asar アーカイブをファイルとして読み込む必要があります。この目的のために、 asar サポートしないオリジナルの fs API を提供するビルトインの original-fs モジュールを使用できます。

var originalFs = require('original-fs');
originalFs.readFileSync('/path/to/example.asar');

process.noAssartrue をセットしても fs モジュールの asar サポートを無効にすることができます:

process.noAsar = true;
fs.readFileSync('/path/to/example.asar');

Node API の制限

Node APIで、asar アーカイブが可能な限りディレクトリのように動作するよう懸命に試してますが、低レベル環境での Node API に起因した制限が幾つかあります。

アーカイブは読み取り専用です

アーカイブは修正できないため、ファイルを変更できる変更できる全ての Node API は asar アーカイブに対して動作しません。

作業ディレクトリは、アーカイブ内のディレクトリに設定できません

asar アーカイブはディレクトリのように扱われるにも関わらず、ファイルシステム上には実際のディレクトリが存在しないため、asar アーカイブ内のディレクトリを作業ディレクトリとして設定することはできません。幾つかの API の cwd オプションにアーカイブ内のディレクトリを渡すのも同様にエラーの原因になります。

いくつかのAPIで追加のアンパッキングがされます

たいていの fs APIは、アンパッキングせずに、 asar アーカイブからファイルを読み込んだり、ファイル情報を取得できます。しかし、システムコールに実際のファイルパスを渡すようになっている幾つかの API では、Electron は必要なファイルを一時ファイルとして抽出し、API に一時ファイルのパスを渡して、API が動作するようにします。このため、当該 API には多少のオーバーヘッドがあります。

追加のアンパッキングに必要なAPIです:

  • child_process.execFile
  • child_process.execFileSync
  • fs.open
  • fs.openSync
  • process.dlopen - ネイティブモジュール上の require で使用されます

fs.stat の偽の統計情報

asar アーカイブ内のファイルはファイルシステム上に存在しないので、fs.stat および asar アーカイブ内のファイルへの関連情報によって返されるStats オブジェクトは、推測して生成されます。ファイルサイズの取得とファイルタイプのチェックを除いて、 Stats オブジェクトを信頼すべきではありません。

asar アーカイブ内のバイナリの実行

child_process.execchild_process.spawnchild_process.execFile のようなバイナリを実行できるNode APIがあります。しかし、execFile だけが、asar アーカイブ内でのバイナリ実行をサポートしています。

なぜならば、execspawn は入力として file の代わりに command を受け取り、command はシェル配下で実行されるからです。コマンドが asar アーカイブ内のファイルを使うかどうかを決定するための信頼できる方法はありませんし、そうするとしてもコマンドで使うファイルパスを副作用なしに置き換えることができるかどうかを確認することはできません。

asar アーカイブ内のファイルをアンパックして追加

上記のように、いくつかのNode APIが呼ばれると、ファイルシステム上にファイルをアンパックしますが,パフォーマンス問題は別として、ウィルススキャナーのアラートにつながる可能性があります。

これに対応するために、--unpack オプションを使用して、アーカイブを作成する際に、いくつかのファイルをアンパックできます。例えば、ネイティブモジュールの共有ライブラリを除く場合:

$ asar pack app app.asar --unpack *.node

このコマンドを実行した後、app.asar とは別に、アンパックされたファイルを含んだapp.asar.unpacked フォルダーが生成されます。ユーザーに提供するときには、app.asar と一緒にコピーしなければなりません。