Skip to content

Bun のバンドラーは、TypeScript または JavaScript ファイルからスタンドアロンバイナリを生成するための --compile フラグを実装しています。

bash
bun build ./cli.ts --compile --outfile mycli
ts
console.log("Hello world!");

これにより、cli.ts が直接実行可能な実行可能ファイルにバンドルされます。

bash
./mycli
txt
Hello world!

インポートされたすべてのファイルとパッケージは、Bun ランタイムのコピーと一緒に実行可能ファイルにバンドルされます。すべての組み込み Bun および Node.js API がサポートされています。


他のプラットフォームへのクロスコンパイル

--target フラグを使用すると、bun build を実行しているマシンとは異なるオペレーティングシステム、アーキテクチャ、または Bun のバージョン向けにスタンドアロン実行可能ファイルをコンパイルできます。

Linux x64(ほとんどのサーバー)用にビルドするには:

bash
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp

# 2013 年以前の CPU をサポートするには、ベースラインバージョン(nehalem)を使用
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp

# 2013 年以降の CPU のみを明示的にサポートするには、モダンバージョン(haswell)を使用
# モダンの方が高速ですが、ベースラインの方が互換性が高いです。
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp

Linux ARM64(例:Graviton または Raspberry Pi)用にビルドするには:

bash
# 注:アーキテクチャが指定されていない場合、デフォルトのアーキテクチャは x64 です。
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp

Windows x64 用にビルドするには:

bash
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp

# 2013 年以前の CPU をサポートするには、ベースラインバージョン(nehalem)を使用
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp

# 2013 年以降の CPU のみを明示的にサポートするには、モダンバージョン(haswell)を使用
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp

# 注:.exe 拡張子が提供されていない場合、Bun は Windows 実行可能ファイル用に自動的に追加します

macOS arm64 用にビルドするには:

bash
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp

macOS x64 用にビルドするには:

bash
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp

サポートされているターゲット

--target フラグの順序は、- で区切られている限り重要ではありません。

--targetオペレーティングシステムアーキテクチャモダンベースラインLibc
bun-linux-x64Linuxx64glibc
bun-linux-arm64Linuxarm64N/Aglibc
bun-windows-x64Windowsx64-
bun-windows-arm64Windowsarm64-
bun-darwin-x64macOSx64-
bun-darwin-arm64macOSarm64N/A-
bun-linux-x64-muslLinuxx64musl
bun-linux-arm64-muslLinuxarm64N/Amusl

ビルド時定数

--define フラグを使用して、バージョン番号、ビルドタイムスタンプ、または設定値などのビルド時定数を実行可能ファイルに注入します。

bash
bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycli

これらの定数は、実行時にオーバーヘッドがなく、デッドコード削除の最適化を可能にするために、コンパイルされたバイナリに直接埋め込まれます。

NOTE

包括的な例と高度なパターンについては、[ビルド時定数ガイド](/ja/guides/runtime/build-time-constants) を参照してください。

本番環境へのデプロイ

コンパイルされた実行可能ファイルは、メモリ使用量を削減し、Bun の起動時間を改善します。

通常、Bun は import および require で JavaScript および TypeScript ファイルを読み取り、トランスパイルします。これが Bun の多くの部分が「そのまま動作する」理由の一部ですが、無料ではありません。ディスクからファイルを読み取り、ファイルパスを解決し、解析し、トランスパイルし、ソースコードを印刷するには、時間とメモリがかかります。

コンパイルされた実行可能ファイルを使用すると、そのコストをランタイムからビルド時に移動できます。

本番環境にデプロイする際は、次を推奨します。

bash
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp

バイトコードコンパイル

起動時間を改善するには、バイトコードコンパイルを有効にします。

bash
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myapp

バイトコードコンパイルを使用すると、tsc は 2 倍速く起動します。

バイトコードコンパイルは、大きな入力ファイルの解析オーバーヘッドをランタイムからバンドル時間に移動します。アプリはより速く起動しますが、bun build コマンドが少し遅くなるトレードオフです。ソースコードを難読化することはありません。

これらのフラグの役割

--minify 引数は、トランスパイルされた出力コードのサイズを最適化します。大規模なアプリケーションの場合、これはメガバイト単位のスペースを節約できます。小規模なアプリケーションの場合、起動時間を少し改善する可能性もあります。

--sourcemap 引数は、zstd で圧縮されたソースマップを埋め込み、エラーとスタックトレースがトランスパイルされた場所ではなく元の場所を指すようにします。Bun はエラー発生時にソースマップを自動的に解凍して解決します。

--bytecode 引数は、バイトコードコンパイルを有効にします。Bun で JavaScript コードを実行するたびに、JavaScriptCore(エンジン)はソースコードをバイトコードにコンパイルします。この解析作業をランタイムからバンドル時間に移動し、起動時間を節約できます。


ランタイム引数の埋め込み

--compile-exec-argv="args" - process.execArgv を介して利用可能なランタイム引数を埋め込みます。

bash
bun build --compile --compile-exec-argv="--smol --user-agent=MyBot" ./app.ts --outfile myapp
ts
// コンパイルされたアプリ内
console.log(process.execArgv); // ["--smol", "--user-agent=MyBot"]

自動設定読み込みの無効化

デフォルトでは、スタンドアロン実行可能ファイルは、実行可能ファイルが実行されるディレクトリの .env および bunfig.toml ファイルを検索します。ユーザーの作業ディレクトリに関係なく決定論的な実行のために、ビルド時にこの動作を無効にできます。

bash
# .env 読み込みを無効化
bun build --compile --no-compile-autoload-dotenv ./app.ts --outfile myapp

# bunfig.toml 読み込みを無効化
bun build --compile --no-compile-autoload-bunfig ./app.ts --outfile myapp

# 両方を無効化
bun build --compile --no-compile-autoload-dotenv --no-compile-autoload-bunfig ./app.ts --outfile myapp

JavaScript API を介してこれを設定することもできます。

ts
await Bun.build({
  entrypoints: ["./app.ts"],
  compile: {
    autoloadDotenv: false, // .env 読み込みを無効化
    autoloadBunfig: false, // bunfig.toml 読み込みを無効化
  },
});

Bun CLI として動作

NOTE

Bun v1.2.16 で新規

BUN_BE_BUN=1 環境変数を設定することで、スタンドアロン実行可能ファイルを bun CLI そのものとして実行できます。この変数が設定されている場合、実行可能ファイルはバンドルされたエントリーポイントを無視し、Bun の CLI のすべての機能を公開します。

例えば、シンプルなスクリプトからコンパイルされた実行可能ファイルを考えてみましょう。

bash
echo "console.log(\"you shouldn't see this\");" > such-bun.js
bun build --compile ./such-bun.js
txt
[3ms] bundle 1 modules
[89ms] compile such-bun

通常、./such-bun を引数付きで実行すると、スクリプトが実行されます。

bash
# 実行可能ファイルはデフォルトで独自のエントリーポイントを実行
./such-bun install
txt
you shouldn't see this

ただし、BUN_BE_BUN=1 環境変数を使用すると、bun バイナリと同じように動作します。

bash
# 環境変数を使用すると、実行可能ファイルは `bun` CLI として動作
BUN_BE_BUN=1 ./such-bun install
txt
bun install v1.2.16-canary.1 (1d1db811)
Checked 63 installs across 64 packages (no changes) [5.00ms]

これは、パッケージのインストール、依存関係のバンドル、異なるファイルまたはローカルファイルの実行などを行う必要がある Bun 上で CLI ツールをビルドする場合に役立ち、別のバイナリをダウンロードしたり Bun をインストールしたりする必要がありません。


フルスタック実行可能ファイル

NOTE

Bun v1.2.17 で新規

Bun の --compile フラグは、サーバーコードとクライアントコードの両方を含むスタンドアロン実行可能ファイルを作成でき、フルスタックアプリケーションに最適です。サーバーコードで HTML ファイルをインポートすると、Bun はすべてのフロントエンドアセット(JavaScript、CSS など)を自動的にバンドルし、それらを実行可能ファイルに埋め込みます。Bun がサーバーで HTML インポートを検出すると、JavaScript、CSS、およびその他のアセットをバンドルするフロントエンドビルドプロセスを開始します。

ts
import { serve } from "bun";
import index from "./index.html";

const server = serve({
  routes: {
    "/": index,
    "/api/hello": { GET: () => Response.json({ message: "Hello from API" }) },
  },
});

console.log(`Server running at http://localhost:${server.port}`);
html
<!DOCTYPE html>
<html>
  <head>
    <title>My App</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <h1>Hello World</h1>
    <script src="./app.ts"></script>
  </body>
</html>
ts
console.log("Hello from the client!");
css
body {
  background-color: #f0f0f0;
}

これを単一の実行可能ファイルにビルドするには:

bash
bun build --compile ./server.ts --outfile myapp

これにより、次を含む自己完結型バイナリが作成されます。

  • サーバーコード
  • Bun ランタイム
  • すべてのフロントエンドアセット(HTML、CSS、JavaScript)
  • サーバーで使用される npm パッケージ

その結果、Node.js、Bun、またはインストールされた依存関係を必要とせずにどこにでもデプロイできる単一ファイルになります。実行するだけです。

bash
./myapp

Bun は、適切な MIME タイプとキャッシュヘッダーでフロントエンドアセットを提供することを自動的に処理します。HTML インポートは、Bun.serve が事前バンドルされたアセットを効率的に提供するために使用するマニフェストオブジェクトに置き換えられます。

Bun でフルスタックアプリケーションをビルドする詳細については、フルスタックガイド を参照してください。


ワーカー

スタンドアロン実行可能ファイルでワーカーを使用するには、ワーカーのエントリーポイントを CLI 引数に追加します。

bash
bun build --compile ./index.ts ./my-worker.ts --outfile myapp

次に、コード内でワーカーを参照します。

ts
console.log("Hello from Bun!");

// これらすべてが機能します:
new Worker("./my-worker.ts");
new Worker(new URL("./my-worker.ts", import.meta.url));
new Worker(new URL("./my-worker.ts", import.meta.url).href);

複数のエントリーポイントを実行可能ファイルに追加すると、それらは実行可能ファイル内に個別にバンドルされます。

将来的には、new Worker(path) で静的に既知のパスの使用を自動的に検出し、それらを実行可能ファイルにバンドルする可能性がありますが、現時点では、上記の例のようにシェルコマンドに手動で追加する必要があります。

スタンドアロン実行可能ファイルに含まれていないファイルへの相対パスを使用すると、プロセスの現在の作業ディレクトリからのそのパスをディスクから読み込もうとします(存在しない場合はエラーになります)。


SQLite

bun:sqlite インポートを bun build --compile で使用できます。

デフォルトでは、データベースはプロセスの現在の作業ディレクトリに対して解決されます。

ts
import db from "./my.db" with { type: "sqlite" };

console.log(db.query("select * from users LIMIT 1").get());

これは、実行可能ファイルが /usr/bin/hello にあり、ユーザーのターミナルが /home/me/Desktop にある場合、/home/me/Desktop/my.db を検索することを意味します。

bash
cd /home/me/Desktop
./hello

アセットとファイルの埋め込み

スタンドアロン実行可能ファイルはファイルの埋め込みをサポートしています。

bun build --compile でファイルを埋め込むには、コード内でファイルをインポートします。

ts
// これは内部ファイルパスになります
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // 埋め込まれたファイルは Response オブジェクトからストリーミングできます
    return new Response(file(icon));
  },
};

埋め込まれたファイルは、Bun.file の関数または Node.js fs.readFile 関数("node:fs" 内)を使用して読み取れます。

例えば、埋め込まれたファイルの内容を読み取るには:

ts
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

const bytes = await file(icon).arrayBuffer();
// await fs.promises.readFile(icon)
// fs.readFileSync(icon)

SQLite データベースの埋め込み

アプリケーションが SQLite データベースを埋め込みたい場合は、インポート属性で type: "sqlite" を設定し、embed 属性を "true" に設定します。

ts
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };

console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());

このデータベースは読み書き可能ですが、実行可能ファイルが終了するとすべての変更が失われます(メモリに保存されるため)。

N-API アドオンの埋め込み

.node ファイルを実行可能ファイルに埋め込むことができます。

ts
const addon = require("./addon.node");

console.log(addon.hello());

残念ながら、@mapbox/node-pre-gyp やその他の同様のツールを使用している場合、.node ファイルが直接 require されていないと正しくバンドルされないため、注意が必要です。

ディレクトリの埋め込み

bun build --compile でディレクトリを埋め込むには、bun build コマンドでシェルグロブを使用します。

bash
bun build --compile ./index.ts ./public/**/*.png

次に、コード内でファイルを参照できます。

ts
import icon from "./public/assets/icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // 埋め込まれたファイルは Response オブジェクトからストリーミングできます
    return new Response(file(icon));
  },
};

これは正直なところ回避策であり、将来的にはより直接的な API でこれを改善することを期待しています。

埋め込まれたファイルのリスト

埋め込まれたすべてのファイルのリストを取得するには、Bun.embeddedFiles を使用します。

ts
import "./icon.png" with { type: "file" };
import { embeddedFiles } from "bun";

console.log(embeddedFiles[0].name); // `icon-${hash}.png`

Bun.embeddedFiles は、ファイルのサイズ、内容、およびその他のプロパティを取得するために使用できる Blob オブジェクトの配列を返します。

ts
embeddedFiles: Blob[]

埋め込まれたファイルのリストには、.ts および .js ファイルなどのバンドルされたソースコードは含まれていません。

コンテンツハッシュ

デフォルトでは、埋め込まれたファイルにはコンテンツハッシュが名前に追加されます。これは、URL または CDN からファイルを提供し、キャッシュの無効化の問題を減らしたい場合に役立ちます。しかし、時にはこれは予期せぬことで、元の代わりに名前を取得したい場合があります。

コンテンツハッシュを無効にするには、--asset-namingbun build --compile に次のように渡します。

bash
bun build --compile --asset-naming="[name].[ext]" ./index.ts

ミニファイ

実行可能ファイルのサイズを少し削減するには、--minifybun build --compile に渡します。これにより、Bun のミニファイヤーを使用してコードサイズを削減します。全体的に、Bun のバイナリはまだ大きすぎて、小さくする必要があります。


Windows 固有のフラグ

Windows でスタンドアロン実行可能ファイルをコンパイルする際、生成された .exe ファイルのメタデータをカスタマイズするために使用できる 2 つのプラットフォーム固有のオプションがあります。

  • --windows-icon=path/to/icon.ico - 実行可能ファイルのアイコンをカスタマイズします。
  • --windows-hide-console - TTY を必要としないアプリケーションのために、バックグラウンドターミナルを無効にします。

macOS でのコード署名

macOS でスタンドアロン実行可能ファイルをコード署名するには(Gatekeeper の警告を修正)、codesign コマンドを使用します。

bash
codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myapp

JIT 権限を持つ entitlements.plist ファイルを含めることを推奨します。

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
</dict>
</plist>

JIT サポートでコード署名するには、codesign--entitlements フラグを渡します。

bash
codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myapp

コード署名後、実行可能ファイルを検証します。

bash
codesign -vvv --verify ./myapp
./myapp: valid on disk
./myapp: satisfies its Designated Requirement

コードスプリッティング

スタンドアロン実行可能ファイルはコードスプリッティングをサポートしています。--compile--splitting を使用して、ランタイムにコードスプリットチャンクを読み込む実行可能ファイルを作成します。

bash
bun build --compile --splitting ./src/entry.ts --outdir ./build
ts
console.log("Entrypoint loaded");
const lazy = await import("./lazy.ts");
lazy.hello();
ts
export function hello() {
  console.log("Lazy module loaded");
}
bash
./build/entry
txt
Entrypoint loaded
Lazy module loaded

サポートされていない CLI 引数

現在、--compile フラグは一度に 1 つのエントリーポイントのみを受け入れ、次のフラグをサポートしていません。

  • --outdir--splitting を使用する場合を除き、代わりに outfile を使用します。
  • --public-path
  • --target=node または --target=browser
  • --no-bundle - すべてを実行可能ファイルにバンドルします。

Bun by www.bunjs.com.cn 編集