メインコンテンツへ飛ぶ

ASAR Archives

After creating an application distribution, the app's source code are usually bundled into an ASAR archive, which is a simple extensive archive format designed for Electron apps. By bundling the app we can mitigate issues around long path names on Windows, speed up require and conceal your source code from cursory inspection.

The bundled app runs in a virtual file system and most APIs would just work normally, but for some cases you might want to work on ASAR archives explicitly due to a few caveats.

Using ASAR Archives

Electron には、2 組の API があります。Node.js により提供される Node API、そして Chromium により提供されるウェブ API です。 Both APIs support reading files from ASAR archives.

Node API

With special patches in Electron, Node APIs like fs.readFile and require treat ASAR archives as virtual directories, and the files in it as normal files in the filesystem.

例えば、/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

Read a file in the ASAR archive:

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')

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

const { BrowserWindow } = require('electron')
const win = new BrowserWindow()

win.loadURL('file:///path/to/example.asar/static/index.html')

Web API

ウェブページで、アーカイブ内のファイルを file: プロトコルでリクエストできます。 Like the Node API, ASAR archives are treated as directories.

例えば、$.get でファイルを取得するには:

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

Treating an ASAR archive as a Normal File

For some cases like verifying the ASAR archive's checksum, we need to read the content of an ASAR archive as a file. この目的のために、 asar サポートしないオリジナルの fs API を提供するビルトインの original-fs モジュールを使用できます。

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

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

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

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.

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

The archives can not be modified so all Node APIs that can modify files will not work with ASAR archives.

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

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. いくつかの API の cwdの引数としてアーカイブ内のディレクトリを渡すのも同様にエラーの原因になります。

いくつかの API で余分な展開がされる

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. このため、当該 API には多少のオーバーヘッドがあります。

追加の展開が必要なAPIです:

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

fs.stat の偽の統計情報

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

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.

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

Adding Unpacked Files to ASAR archives

上で述べたように、いくつかの Node API は、呼び出されたときにファイルをファイルシステムに解凍します。 パフォーマンスの問題とは別に、この動作によってさまざまなウイルス対策スキャナが起動される可能性があります。

回避策として、--unpack オプションを使用して様々なファイルを解凍したままにできます。 以下の例では、ネイティブ Node.js モジュールの共有ライブラリはパッケージされません。

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

コマンドを実行すると、app.asar.unpacked という名前のフォルダが app.asar ファイルとともに作成されていることがわかります。 それには解凍されたファイルが含まれており、app.asar アーカイブと共に送られる必要があります。