Bun で実行可能バイナリをクロスコンパイルできるようになりました
はじめに
#去年の9月 Bun が 1.0 に到達したとき、開発環境に導入してみた記事を書きました。
その後 Bun 1.1 で Windows 対応が行われ、真のクロスプラットフォームが実現されました。
実行可能バイナリを生成する機能は提供されていましたが、1.1.5 でクロスコンパイルの機能が実装されました。
冒頭で紹介した記事がきっかけで、Software Design 2024年6月号第2特集の Bun に寄稿する機会を得ました。以下のように Bun の概要から利用方法、Node.js とのパフォーマンス比較を網羅する特集です。
- 第1章: Bun の全体像をつかむ
- 第2章: Bun を使ってみよう
- 第3章: Bun と Node.js の徹底比較
筆者は2章の執筆を担当させていただきました。Bun のインストールから各機能の紹介と利用方法、デバッグ方法などについて書きました。執筆時点では Bun 1.1 のリリース直後で、クロスコンパイルについては触れられませんでした。実行可能バイナリの作成については紹介しています。
第3章は Node.js と Bun のコードを AWS Lambda にデプロイして速度比較するなど、興味深い内容となっています。
シングルバイナリおよびクロスコンパイルの利点
#シングルバイナリ化することのメリットは、ユーザーに対する配布の利便性はもちろんのこと、以下のような利点もあります。
- 実行時に import 解決、トランスパイル、コード生成の処理が不要になるため時間とメモリが節約できる
- バイナリのコピーだけでコンテナ化が可能でランタイム不要なので軽量コンテナにできる
- バイナリを CI で利用する場合、ダウンロードしてパスを通すだけで実行できるのでパイプラインがシンプルになり、実行時間の節約になる
さらにクロスコンパイルができると以下のような利点があります。
- 対象の環境ごとにビルド環境を用意する必要がない
- 1つの CI パイプラインで全ターゲットの実行可能バイナリをビルドできる
このため、もともとオールインワンを売りとする Bun にクロスコンパイルの機能が実装されたことで、開発からクロスプラットフォームへの実行可能バイナリ配布まで bun CLI 一つで賄えることになり、開発体験はかなり向上したと言えるでしょう。
Bun のクロスコンパイルを試す
#では、Bun の実行可能バイナリの生成とクロスコンパイルを試してみましょう。筆者は macOS Sonoma / Bun 1.1.8 の環境で実施しています。
Bun のプロジェクトを作成します。
mkdir simple-server && cd simple-server
bun init -y
ポート3000番で待ち受けてメッセージを返すだけの簡単な HTTP サーバーを書きました。
Bun.serve({
port: 3000,
fetch(req) {
return new Response('Hello, Bun!')
}
});
このコードは次のコマンドで実行可能です。
bun index.ts
実行可能バイナリを作成してみます。
$ bun build --compile ./index.ts --outfile simpleServer
[2ms] bundle 1 modules
[104ms] compile simpleServer
約0.1秒でビルドが完了し、macOS のマシンをターゲットとする51MBの実行可能バイナリが生成されました。
$ ls -lh simpleServer
-rwxrwxrwx 1 kondoh staff 51M 5 20 14:50 simpleServer
以下のように bun CLI なしで実行できます。
./simpleServer
上記の例では、ターゲットを指定しませんでしたが --target
オプションでプラットフォームを指定できます。Windows 用のバイナリを生成してみましょう。
$ bun build --compile ./index.ts --target=bun-windows-x64 --outfile simpleServer.exe
[3ms] bundle 1 modules
[4.302s] compile simpleServer.exe bun-windows-x64-v1.1.8
必要なライブラリのダウンロードを含めて4.3秒ほどでビルドが完了しました。ファイルサイズは100MBぐらいです。
$ ls -lh simpleServer.exe
-rwxrwxrwx 1 kondoh staff 105M 5 20 14:55 simpleServer.exe
--target
の指定は以下のようになっています。
プラットフォーム | --target の値 |
---|---|
Linux x64 | bun-linux-x64 |
Linux ARM | bun-linux-arm64 |
Windows x64 | bun-windows-x64 |
macOS x64 | bun-darwin-x64 |
macOS Apple Silicon | bun-darwin-arm64 |
プロダクションへのデプロイ時には、--minify
と --sourcemap
の指定も推奨されています。
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp
--minify
オプションを指定することでトランスパイルされたコードのサイズを小さくできます。--sourcemap
オプションを指定することでオリジナルのソースコードの位置でエラー情報を出力させることが可能です。
その他、アセットの埋め込みや SQLite データベースの埋め込みもサポートされています。詳細はドキュメントを参照してください。
Single-file executable – Runtime | Bun Docs
主要ランタイムでの実装状況
#実行可能バイナリの生成については、Node.js と Deno でも実装されており、クロスコンパイルについては Deno にも既に実装されています。
- deno compile, standalone executables | Deno Docs
- Single executable applications | Node.js v22.2.0 Documentation
Deno | Bun | Node.js | |
---|---|---|---|
実行可能バイナリの生成 | ⚪︎ | ⚪︎ | ⚪︎ (Active development) |
クロスコンパイル | ⚪︎ | ⚪︎ | - |
Node.js の Single Executable Applications に関しては、stability: 1.1 - Active development
のステータスであり、現時点では安定版とは言えません。後発のランタイム Deno と Bun が肩を並べたという状況です。
昨年の記事ですが、本サイトでは Node.js の Single Executable Applications について以下の記事で取り上げています。
Node.js v19.7で実験的に導入された Single Executable Applications で単独実行可能ファイルを作成する
さいごに
#以上、Bun で実装された実行可能バイナリのクロスコンパイルを試してみました。
実行可能バイナリによってデプロイ環境でのフットプリントを小さく起動を速くできることは大きなメリットです。
最終的には、CI でエンドツーエンドのテストをターゲットプラットフォームごとに実施する必要はありますが、クロスコンパイル機能により開発環境は1プラットフォーム分だけあればよいのは嬉しいところです。