TypeScript をバイナリにコンパイル

コマンド1つでmain.ts がスタンドアロンのネイティブ実行ファイルになります。ターゲット マシンに Node.js は不要、バンドルされたランタイムも不要、ユーザー 側のインストール作業も不要です。

terminal

$ perry compile main.ts

✓ Compiled executable: main (2.3 MB)

$ ./main

Hello, World!

“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つとも、誰かに渡せる単一のファイルを生成します。それ以外の点 ではまったく異なるツールであり、それぞれに正解となる相手が います。

Perrybun build --compileNode 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を参照してください。

パフォーマンス比較

ネイティブコンパイルが圧倒的な効率性を実現

指標PerryNode.jsBun
バイナリサイズ2-5 MB~80 MB~90 MB
起動時間~1 ms~30 ms~10 ms
ランタイム依存なしNode.jsBun
メモリオーバーヘッド最小限V8 + GCJSC + GC

ベンチマーク結果: 最大18倍高速

Perry v0.5.279 vs Node.js v25 — RUNS=11 中央値、Apple M1 Max(低いほど良い)

accumulate
18x
object create
11x
json roundtrip
5.3x
loop overhead
4.5x
math intensive
3.6x
array read
3.3x
fibonacci
3.2x
array write
2.3x
loop data dependent
1.4x
nested loops
1.0x
バイナリサイズ低いほど良い
Perry
5 MB
Node.js
80 MB
Bun
90 MB

今日、最初のバイナリをコンパイルしよう

Homebrew、APT、winget でインストールしたら、あとは perry compile main.tsだけです。