“TypeScript のコンパイル”と呼ばれる3つのもの
開発者が「TypeScript をバイナリにコンパイルする方法」を調べると、 同じ言葉を共有する3つのまったく異なる技術に行き当たるのが常です。
- トランスパイル。
tsc、SWC、esbuild は TypeScript を JavaScript に変換します。出力を実行するには 依然として Node.js、Bun、あるいはブラウザが必要です。バイナリ は一切関与しません。 - ランタイム埋め込み。
bun build --compile、deno compile、そして Node.js の Single Executable Applications(SEA)は、バンドル された JavaScript をランタイム一式と連結します。1つのファイル にはなりますが、エンジンはその中に同梱されたままで、プロセス が起動するたびにコードはパースされ JIT コンパイルされます。 - 事前(AOT)ネイティブコンパイル。 これが Perry のやり方です。TypeScript は SWC でパースされ、 型が解決され、ジェネリクスは単相化され、LLVM がマシンコードを 出力します。リンカが生成するのは通常の実行ファイル——Rust、 Go、C++ のツールチェーンが生成するのと同じ種類の成果物です。 バイナリの中に JavaScript エンジンはまったく存在しません。
起動するエンジンも、起動時にパースするものもないため、Perry の バイナリは約1ミリ秒で起動します。パイプラインそのものについてはTypeScript ネイティブコンパイラのページとコンパイラ内部構造でさらに詳しく説明しています。
バイナリの大きさは?
実際に使うコードだけがコンパイル・リンクされるため、サイズは 何を取り込むかによって決まります。
- hello world はおよそ 330 KB。
- 一般的な CLI ツールは 2–5 MBに収まります。
- 大きなフレームワーク(Fastify、mysql2 など)をリンクするフル アプリケーションでもおよそ 48 MBです。
比較として:Node SEA の実行ファイルは node バイナリそのもののコピーであるため、コードを追加する前の時点で プラットフォームによっては約88–118 MBから始まり、Bun でコンパイル された hello world は macOS arm64 で約60 MB、Linux x64 で約100 MB 前後になります——Bun ランタイム一式が丸ごと埋め込まれるためです。
Perry vs bun build --compile vs Node SEA
3つとも、誰かに渡せる単一のファイルを生成します。それ以外の点 ではまったく異なるツールであり、それぞれに正解となる相手が います。
| Perry | bun build --compile | Node SEA | |
|---|---|---|---|
| 生成されるもの | AOT コンパイル済みマシンコード(LLVM) | バンドルされた JS + 埋め込み Bun ランタイム | バンドルされたスクリプトを注入した node バイナリのコピー |
| 実行モデル | ネイティブコード、JS エンジンなし | 実行時に JIT(JavaScriptCore) | 実行時に JIT(V8) |
| hello world のサイズ | ~330 KB | ~60 MB(macOS arm64)〜100 MB超(Linux/Windows) | ~88–118 MB(node バイナリのサイズ) |
| 起動時間 | ~1 ms | ~10 ms | ~30 ms |
| クロスコンパイル | 10ターゲット、Linux から Windows/macOS/iOS への クロスコンパイルを含む | 可能——--target 経由で Linux、Windows、macOS | 不可——代わりにプラットフォームごとの node バイナリを コピーする |
| JS / npm 互換性 | 拡大中:axios、zod v4、express、fastify、hono は ネイティブにコンパイル可能。それ以外はオプションの V8 フォールバック | 完全——Bun ランタイムそのものなので | 完全な Node セマンティクス。事前バンドルが必要、 Node 24 LTS では CommonJS のみ |
| ステータス | 1.0 未満 | 安定版 | Node 24 LTS では“Active development”の 安定度 |
正直な整理をすると:アプリケーションが npm エコシステム全体に 依存していて互換性リスクをゼロにしたいなら、Bun と Node SEA は すでに開発対象としているエンジンのセマンティクスをそのまま実行 します——それが彼らの強みであり、デプロイ先によってはサイズの コストは問題にならないかもしれません。Perry は違う賭けです。 真の事前コンパイル、小さなバイナリ、ミリ秒単位の起動を手に 入れる代わりに、V8 から受け継いだものではなく計測・公開されて いる(test262:String 79%、Array 72%、v0.5.1146 時点)1.0 未満 のコンパイラを採用することになります。
詳しい比較:Perry vs Bun とPerry vs Deno。npm パッケージがどのようにコンパイルされるかについては、Real npm packages and a conformance sweepを参照してください。