TypeScriptをそのまま書いて、Node.jsもElectronも不要なスタンドアロンバイナリを作れたら—。その問いに対する実装がRustとLLVMで構築されたネイティブTypeScriptコンパイラ「Perry」(GitHub: PerryTS/perry)だ。2026年4月時点でGitHubスター304を獲得し、急速に注目が集まっている。
perry compile src/main.ts -o myappの1コマンドでmacOS・Windows・Linux・iOS・Android・Webのネイティブバイナリが生成でき、出力サイズはHello Worldで約330KB。Node.jsより最大38倍高速なベンチマーク結果を公式が公開し、Rust・C++と肩を並べるパフォーマンスを一部のベンチマークで達成している。
この記事では、Perryが「何をどこまでできるか」を、RustとLLVMを採用した技術的背景とともに詳しく解説する。
Perryとは—TypeScriptをネイティブコンパイルするRust製コンパイラ
Perryは「One codebase. Every platform. Native performance.」をコンセプトに掲げるTypeScriptコンパイラだ。既存のランタイム(Node.js・Bun・Deno等)がTypeScriptを実行時に変換・解釈するのに対し、PerryはTypeScriptを直接コンパイルしてネイティブマシンコードを生成する。
Perryのパイプラインは、SWC(Rust製TypeScriptパーサー)でASTを生成し、HIR(High-level Intermediate Representation)を経由してLLVM IRに変換し、LLVMが最終的なネイティブバイナリを出力する、という多段階の変換で構成されている。
既存のTypeScriptエコシステムとの最大の差は「実行モデル」だ。Node.jsやBunはJITコンパイラを内蔵するV8エンジンまたは独自エンジンが実行時にコードを最適化するのに対し、PerryはAOT(事前コンパイル)方式で実行前に全ての最適化を済ませる。JITウォームアップ時間がなく、最初の命令から最高速で動作するため、CLIツールやサーバーレス関数のようなコールドスタートが重要なシナリオで特に有利だ。
コードベースの規模は2026年4月時点で約900万行のRustコード(一部Kotlin・Swift・JavaScript・GoなどのUI/テスト関連コードを含む)で構成されており、コンパイラ本体・ランタイム・UIライブラリ・stdlibのRust実装が1リポジトリに収まっている。
バージョン0.5.0からコードジェネレーターをCraneliftからLLVMに完全移行した。初期のLLVM導入時は多くのベンチマークでパフォーマンスが大幅に悪化したが(method_callsが16ms→1,084msに悪化)、その後スカラー置換・インラインバンプアロケーター・整数最適化等の改善で現在はCranelift時代を大幅に上回る性能を達成している。
Perryでできること—主な機能の全体像
Perryが提供する機能は、単なる「TypeScript→バイナリ変換」にとどまらない。クロスプラットフォーム対応、npmパッケージのネイティブ実装、ReactコンポーネントのネイティブUI変換、プラグインシステム、UIテスト基盤など、フルスタックのアプリケーション開発環境として設計されている。
以下に主要機能を整理する:
| 機能カテゴリ | 内容 |
|---|---|
| ネイティブバイナリ生成 | TypeScript→単一バイナリ(330KB〜)、外部依存なし |
| クロスプラットフォーム | macOS/Windows/Linux/iOS/tvOS/watchOS/Android/Web/WASM |
| ホーム画面ウィジェット | iOS・Android・Wear OSウィジェットのコンパイル対応 |
| npmパッケージ | fastify・mysql2・redis等をRustでネイティブ実装 |
| perry-react | ReactコンポーネントをネイティブUIウィジェットに変換 |
| プラグインシステム | TypeScript→共有ライブラリ(.dylib/.dll)出力 |
| Geisterhand(UIテスト) | HTTP駆動のネイティブUIテストフレームワーク組み込み |
| クラウドビルド | perry publishでクロスコンパイル・署名・配布を自動化 |
| 国際化(i18n) | ソースから翻訳文字列を自動抽出 |
ネイティブバイナリの生成と特徴
Perryが生成するバイナリは、実行時に一切の外部依存を持たない。Node.jsのnode_modulesもランタイムDLLも不要で、単一ファイルを配布するだけでアプリが動く。
・Hello World:約330KB
・標準CLIアプリ(fs/path/process使用):約380KB
・フルスタックWebアプリ(fastify・mysql2等含む):約48MB
・V8ランタイム組み込み(--enable-js-runtime):上記+約15MB
Perryは使用するstdlibのみをリンクするため、importしたパッケージのうち実際に使用した部分だけがバイナリに含まれる。
自動デッドコード除去により、importした関数のうち実際に呼ばれるものだけがバイナリに含まれる。巨大なnpmパッケージをimportしても、使用した関数のみがコンパイルされる設計だ。これは静的リンクとLLVMのLTO(Link Time Optimization)によって実現されている。
コールドスタートの速さも特徴のひとつだ。Node.jsはランタイムの初期化・JITコンパイルのウォームアップに数十〜数百ミリ秒かかる場合があるが、Perryのバイナリは直接マシンコードを実行するため、コールドスタートは事実上ゼロに近い。MongoDBのGUIクライアントMango(perryで構築)がサブ秒コールドスタートを実現しているのも、このアーキテクチャによる。
クロスプラットフォームコンパイル
Perryが対応するターゲットプラットフォームは以下の通り:
| ターゲット | フラグ | 備考 |
|---|---|---|
| macOS(ARM64/x86_64) | (デフォルト) | Homebrewでインストール可 |
| Windows | --target windows |
wingetインストール対応 |
| Linux(Debian/Ubuntu) | --target linux |
APTリポジトリ対応 |
| iOS | --target ios |
UIKitネイティブ |
| iOS Simulator | --target ios-simulator |
|
| tvOS | --target tvos |
|
| watchOS | --target watchos |
|
| Android | --target android |
|
| Web(JS生成) | --target web |
|
| WebAssembly | --target wasm |
|
| iOSホーム画面ウィジェット | --target ios-widget |
SwiftUIコードジェネレーター |
| Androidウィジェット | --target android-widget |
Glanceコードジェネレーター |
| Wear OS タイル | --target wearos-tile |
|
| watchOS ウィジェット | --target watchos-widget |
ホーム画面ウィジェット対応は特に注目で、TypeScriptを書くだけでiOSのWidgetKit・AndroidのGlance API・Wear OS Tilesのウィジェットが作成できる。 バックエンドではSwiftUI(iOS/tvOS/watchOS向け)とAndroid Glance API(Wear OS向け)のコードジェネレーターがそれぞれ独立したクレートとして実装されており、プラットフォーム固有のコードを自動生成する。
perry publish <platform>コマンドと組み合わせると、ローカルのTypeScriptソースをクラウドビルドサーバー「perry-hub」に送信し、各プラットフォーム向けのクロスコンパイル・コード署名・App Store/Google Play公開を1コマンドで完結させることができる。macOSのコード署名、iOSのプロビジョニングプロファイル管理など、ネイティブアプリ配布で発生する煩雑な作業をPerry CLIが吸収する設計だ。
npmパッケージのネイティブ実装
通常のnpmパッケージはJavaScriptとして動作するためJavaScriptランタイムを必要とするが、Perryはよく使われるパッケージをRustでネイティブ実装しており、--enable-js-runtimeなしで使用できる:
| カテゴリ | ネイティブ実装済みパッケージ |
|---|---|
| HTTP | fastify, axios, node-fetch, ws(WebSocket) |
| データベース | mysql2, pg(PostgreSQL), ioredis(Redis) |
| 認証・暗号 | bcrypt, argon2, jsonwebtoken |
| ユーティリティ | dotenv, uuid, nodemailer, zlib, node-cron |
これらのパッケージはRustのTokioランタイム上で非同期I/Oを処理し、V8エンジンを介さずに動作する。結果として、Node.jsでは難しかった「npmパッケージを使いながらネイティブバイナリを出力する」という要件を満たしている。
package.jsonのperryフィールドに`compilePackages`を指定すると、npmパッケージをV8ランタイム経由ではなくネイティブコードとしてコンパイルできる。
数値計算・暗号ライブラリ・データ構造など、I/Oを持たない純粋計算系パッケージに特に効果的。HTTP/WebSocket・ネイティブアドオン依存パッケージはV8経由で使うことが推奨されている。
ReactコンポーネントをネイティブUIに変換する「perry-react」
Perryエコシステムで特にユニークな機能が、perry-reactパッケージだ。標準的なReact/JSXのコードを書くと、ブラウザのDOMではなくOSネイティブのUIウィジェットにコンパイルされる。
macOSではAppKit、iOSではUIKit、tvOSではTVUIKit、watchOSではWatchKit、AndroidではAndroid View Systemのコンポーネントにそれぞれマッピングされ、プラットフォーム固有のルック&フィールを持つネイティブアプリが生成される。
useState・useEffect・useCallbackなど標準Reactフックはそのまま動作し、TypeScriptの型チェックも効く。Reactを知っているエンジニアが、追加学習コストなしにネイティブアプリを作れる設計となっている。
React Nativeとの根本的な違いは「ブリッジの有無」だ。React NativeはJavaScriptエンジンとネイティブ側をブリッジで接続し、実行時に通信するアーキテクチャを取る。perry-reactはコンパイル時にReactコンポーネントをネイティブUIコードに変換するため、ブリッジのオーバーヘッドが発生しない。実行バイナリにJavaScriptエンジンは含まれない。
実際にperryで構築されたMongoDBクライアントMango(MangoQuery/app)の画面はTypeScript+perry-reactで作られたネイティブアプリの実例だ:

Mangoは約7MBのバイナリサイズ、100MB未満のRAM使用量、サブ秒のコールドスタートを実現している。同等機能のElectronアプリが通常150MB超のバイナリになることと比較すると、その差は明らかだ。
プラグインシステム
Perryは共有ライブラリ(動的ライブラリ)としてコンパイルする機能も持つ。--output-type dylibフラグを指定することで、TypeScriptコードを.dylib(macOS/Linux)や.dll(Windows)として出力できる。
この仕組みを使うと、TypeScriptで書いたロジックをC・Rust・Go等の他の言語から呼び出せるようになる。PerryプラグインAPIを使えば、AIコードエディタHone(hone.codes)のようなPerry製アプリへのプラグイン拡張も可能だ。既存のエディタをPerryで書き換える際の段階的移行戦略としても使える。
UIテスト基盤「Geisterhand」
Perryには「Geisterhand」と呼ばれる組み込みUIテストフレームワークが付属している。--enable-geisterhandフラグをつけてコンパイルすると、アプリの起動時にHTTPサーバー(デフォルト: localhost:7676)が立ち上がり、HTTP経由でUIを操作・スクリーンショット取得・状態検証ができる。
・全ネイティブプラットフォーム(macOS・iOS・Android・Windows・Linux)でスクリーンショット取得に対応
・HTTP APIでボタンクリック・テキスト入力・画面遷移を自動化
・CI/CDパイプラインに組み込み可能
・テストコード自体はTypeScriptで記述できる
WebベースのPlaywright/Puppeteerと異なり、GeisterhandはネイティブUIを対象としており、macOSのAccessibility API、iOSのXCTest UIInteraction、Androidのuiautomator2などのプラットフォーム固有のUI自動化機構をPerryが抽象化する。
Perryが対応するTypeScript言語機能
Perryは現時点でTypeScriptの主要機能の大部分を実装している。公式のtypescript-compatibility-tests.mdで詳細なテスト結果が公開されている。
| 機能カテゴリ | 対応状況 |
|---|---|
| 変数(let/const/var) | ✅ |
| 全演算子(+, -, *, /, %, **, &, |, ^, «, », ?., ternary等) | ✅ |
| 制御フロー(if/else, for, while, switch, break, continue) | ✅ |
| try-catch-finally, throw | ✅ |
| 関数・アロー関数・rest params・デフォルト引数 | ✅ |
| ミュータブルキャプチャを持つクロージャ | ✅ |
| クラス(継承・プライベートフィールド#・static・getter/setter・super) | ✅ |
| ジェネリクス(コンパイル時にモノモーフ化) | ✅ |
| インターフェース・型エイリアス・ユニオン型・型ガード | ✅ |
| Async/await, Promise | ✅ |
| ジェネレーター(function*) | ✅ |
ESモジュール(import/export・re-export・import * as) |
✅ |
| 分割代入(配列・オブジェクト・rest・デフォルト・リネーム) | ✅ |
| スプレッド演算子 | ✅ |
| RegExp(test, match, replace) | ✅ |
| BigInt(256ビット) | ✅ |
| デコレーター | ✅ |
ジェネリクスはコンパイル時にモノモーフ化(型パラメーターごとに専用の実装を生成)される。これはC++テンプレートと同様の手法で、実行時の型ディスパッチコストをゼロにする代わりにバイナリサイズが増加する可能性がある。型情報はコンパイル後に消去されるため、実行時にジェネリクスの型パラメーターにアクセスすることはできない。
標準ライブラリについては、console・fs・path・process・JSON・Math・Date・crypto・os・Buffer・child_process・Map・Set・setTimeout/setInterval・worker_threadsが実装されており、一般的なCLI・サーバーアプリケーション開発に必要な機能は揃っている。
Rustを採用した理由—コンパイラとランタイムの両方にRustを選ぶ意味
Perryがコンパイラ本体とランタイムの両方にRustを採用したのは、いくつかの明確な理由がある。
メモリ安全性とコンパイラの信頼性
コンパイラは複雑なデータ構造(AST・IR・型情報)を大量に操作するプログラムだ。C++で実装された伝統的なコンパイラ(GCC・Clang等)はメモリバグ(use-after-free・バッファオーバーフロー等)のリスクを常に抱えている。Rustの所有権システムはこれらのバグをコンパイル時に除去し、コンパイラ自体の安定性を保証する。
「コンパイラのバグはユーザーコードのバグよりも発見が難しい」という問題をRustの型システムが根本的に解決するのが、Rustを選ぶ最大の理由の一つだ。コンパイラのバグは誤ったコードを生成するため、バグの影響がユーザーのランタイムエラーとして現れ、根本原因の特定が非常に困難になる。Rustはこのリスクを下げる。
Rayonによる並列コンパイル
Rustのデータ並列ライブラリrayonを使い、複数モジュールのコードジェネレーション・変換パス・シンボルスキャンをCPUコア数に応じて自動並列化している。スレッドセーフティもコンパイル時に保証されるため、並列化起因のレースコンディションが発生しない。
Goの並列化ではsync.Mutexでランタイム排他制御が必要だが、Rustでは型システムが「可変参照が同時に複数存在しないこと」をコンパイル時に保証するため、ロックが不要なケースが多い。これによりrayonのスレッドプールが最大限に活用できる。
LLVMバックエンドへの移行でコンパイル時間は8〜19%増加したが、全体的なコンパイル時間の大部分はSWCパース・HIR変換・リンクであり、バックエンドそのものが支配的ではない。「LLVMは遅い」というイメージとは異なり、Perryの実装では増加幅は小さかった。
ゼロコスト抽象化によるランタイム実装
PerryのランタイムはRustで実装されており、NaN-boxing(64ビットワードで全値を表現する技法)・マークアンドスイープGC・インラインバンプアロケーターなどの低レベル最適化をunsafeコードを交えながら実装している。
IEEE 754のdoble(f64)のNaN表現には多数のビットパターンが未使用のまま残っている。この余剰ビットを使い、「f64の数値」「ポインタ(オブジェクト参照)」「null」「undefined」「boolean」などすべての値を1つの64ビットワードで表現する技法。
V8・SpiderMonkey・WebKitのJSCなど主要なJavaScriptエンジンも採用しており、値の型判定が1回のビット演算で済む。Perryもこれを採用し、ランタイムの値表現コストを最小化している。
GCのアリーナ走査、NaN-boxingのビット操作など、C相当のパフォーマンスが必要な部分でRustのunsafeブロックを使い、その周囲をRustの安全なAPIで包む設計だ。「安全性とパフォーマンスのトレードオフ」ではなく「デフォルト安全、ホットパスのみunsafe」という構成が実現している。
SWCとの統合コスト最小化
SWC(Speedy Web Compiler)はRustで書かれており、Perryと同一言語で記述されているため、FFIを介さずにライブラリとして直接取り込める。異なる言語間の境界でデータを変換するコストがなく、ASTの所有権もRustの型システムで安全に管理できる。
SWCはNext.js・Vercel・Denoなど主要なTypeScriptエコシステムが採用しており、TypeScript仕様への追従も速い。SWCがRust製であることにより、PerryはTypeScriptパーサーを自前で実装せずに済み、代わりに最適化・コードジェネレーション・ランタイムに開発リソースを集中できている。
LLVM IRの直接生成
LLVMのRustバインディング(llvm-sys/inkwell等)を使うことで、LLVM IRを直接生成できる。PythonやGoからLLVMを呼び出す場合と比べ、バインディングの薄さ(ほぼゼロコスト)とRustの型システムによるIR生成の正確性保証が得られる。
LLVM IRは型付きの中間表現であり、Rustの型システムとの親和性が高い。不正なIRの生成をコンパイル時に防ぎやすく、コードジェネレーターのデバッグが容易になる。
Perryのアーキテクチャ—コンパイルパイプラインの全体像
Perryのコンパイルパイプラインは、複数のRustクレートに分割されて動作する:
perry-parser クレート"] B --> C["AST(抽象構文木)"] C --> D["HIR変換
perry-hir クレート
型情報・スコープ解決"] D --> E["変換パス群
perry-transform クレート
クロージャ変換・async展開・インライン化
(Rayonで並列実行)"] E --> F["ターゲット選択
--target フラグ"] F --> G["LLVMコードジェネレーター
perry-codegen"] F --> H["JSコードジェネレーター
perry-codegen-js"] F --> I["WASMコードジェネレーター
perry-codegen-wasm"] F --> J["SwiftUI/Glanceジェネレーター
perry-codegen-swiftui等"] G --> K["LLVM最適化
スカラー置換・fast-math
i64特化・ループカウンター最適化
LICM・FMA・CSE"] K --> L["リンカー呼び出し
Cリンカー必須"] L --> M["ネイティブバイナリ
(perry-runtime+perry-stdlib静的リンク済み)"] H --> N["JavaScriptファイル"] I --> O["WASMバイナリ"] J --> P["SwiftUIコード / Androidコード"]
各クレート(Rustパッケージ)は明確な責務で分割されており、コードジェネレーターはターゲット別に独立している。追加ターゲットは新しいcodegen-*クレートを実装することで拡張できる構造だ。
リポジトリ構成は以下の通り:
perry/
├── crates/
│ ├── perry/ # CLI(compile/run/check/init/doctor/publish)
│ ├── perry-parser/ # SWC TypeScriptパーサー
│ ├── perry-hir/ # HIRデータ構造とAST→HIR変換
│ ├── perry-transform/ # IR変換パス(クロージャ変換・async・インライン化)
│ ├── perry-codegen/ # LLVMネイティブコードジェネレーター
│ ├── perry-codegen-js/ # JavaScriptコードジェネレーター
│ ├── perry-codegen-wasm/ # WebAssemblyコードジェネレーター
│ ├── perry-codegen-swiftui/ # SwiftUIコードジェネレーター
│ ├── perry-codegen-glance/ # Android Glanceウィジェット
│ ├── perry-runtime/ # ランタイム(NaN-boxing・GC・arena・strings)
│ ├── perry-stdlib/ # Node.js API実装(fastify・mysql2・redis等)
│ ├── perry-ui-*/ # ネイティブUI(macOS/iOS/tvOS/watchOS/Android/GTK4/Windows)
│ └── perry-diagnostics/ # エラーレポーティング
ランタイムモデルとしては、シングルスレッドの非同期I/O(TokioのI/Oワーカー+メインスレッドのコールバック)をデフォルトとし、perry/threadパッケージで明示的なマルチスレッドを使えるハイブリッド設計だ。
パフォーマンス—Node.jsを超える数字の根拠
Perryの公式ベンチマーク結果から主要な数値をまとめる(macOS ARM64、Apple Silicon、Node.js v25・Bun 1.3との比較):
| ベンチマーク | Perry | Node.js | Bun | Node.js比 | 内容 |
|---|---|---|---|---|---|
| closure | 8ms | 305ms | 50ms | 38倍高速 | クロージャ生成+呼び出し1000万回 |
| factorial | 24ms | 592ms | 99ms | 24.6倍高速 | 整数累算(整数fast path) |
| method_calls | 2ms | 11ms | 7ms | 5.5倍高速 | クラスメソッドディスパッチ1000万回 |
| loop_overhead | 13ms | 53ms | 51ms | 4倍高速 | タイトな数値ループ1億回 |
| math_intensive | 14ms | 50ms | 51ms | 3.6倍高速 | 調和級数(sqrt/sin/cos) |
| fibonacci(40) | 310ms | 991ms | 514ms | 3.2倍高速 | 再帰関数呼び出し |
| array_read | 4ms | 14ms | 18ms | 3.5倍高速 | 順次読み取り1000万要素 |
| array_write | 2ms | 9ms | 6ms | 4.5倍高速 | 順次書き込み1000万要素 |
クロージャベンチマーク(38倍差)が特に大きい理由は、JavaScriptエンジンがクロージャを動的オブジェクトとして実行時に生成するのに対し、Perryはコンパイル時にクロージャを「ネイティブ関数ポインタ+キャプチャされた変数の構造体」に変換するためだ。 ヒープアロケーションが発生せず、関数呼び出しも直接ジャンプになる。
さらに注目すべきはRust・C++との比較だ。同一のf64演算(TypeScriptのnumber型に対応)で比較すると、Perryは多くのベンチマークでRustに肩を並べるかそれを上回る:
| ベンチマーク | Perry | Rust | C++ | Go | Node.js |
|---|---|---|---|---|---|
| fibonacci | 316ms | 317ms | 308ms | 444ms | 994ms |
| loop_overhead | 12ms | 96ms | 96ms | 96ms | 53ms |
| array_write | 2ms | 6ms | 1ms | 8ms | 8ms |
| math_intensive | 14ms | 48ms | 50ms | 48ms | 49ms |
| nested_loops | 8ms | 8ms | 8ms | 9ms | 16ms |
loop_overheadでPerryがRust・C++・Goより速い(12ms vs 96ms)のは、i32ループカウンターの最適化とreassocfast-mathフラグによるLLVMのARM NEONベクトル化が効いているためだ。厳密なIEEE754準拠が不要なTypeScriptのnumber型の特性を活用し、LLVM最適化パスが並列アキュムレーター+SIMD命令を生成できる。
これらのベンチマークはmacOS ARM64での測定値であり、x86_64・Linux・Windowsでは異なる結果になる可能性がある。また、実際のアプリケーションはI/OバウンドやDB待機が支配的なケースが多く、純粋計算ベンチマークの差がそのままアプリ全体の速度差になるわけではない。
主要な最適化手法の一覧:
- スカラー置換(Scalar Replacement): 非エスケープオブジェクトをレジスタ割り当てのフィールドに分解。ヒープアロケーションをゼロにする
- インラインバンプアロケーター: エスケープするオブジェクトに13サイクルのインラインアリーナバンプを使用(関数呼び出しなし)
- i64特化: 純粋数値の再帰関数をネイティブi64レジスタにコンパイル(f64のラウンドトリップなし)
- 整数剰余fast path:
fptosi → srem → sitofpでfmodを置き換え(factorialで64倍高速化) - i32ループカウンター: ループ変数を整数レジスタで管理(f64ラウンドトリップなし)
- FMA・CSE・ループアンロール: 融合積和演算・共通部分式除去・8倍ループアンロール
競合ツールとの比較
| 特徴 | Perry | Bun | Deno | Node.js | GraalVM |
|---|---|---|---|---|---|
| 実行方式 | AOTネイティブコンパイル | JIT(V8系Bun実装) | JIT(V8) | JIT(V8) | AOT+JIT |
| TypeScript直接実行 | ✅ | ✅ | ✅ | ❌ | 部分的 |
| ネイティブバイナリ出力 | ✅ | ❌(SEA形式) | ❌(SEA形式) | ❌(SEA形式) | ✅ |
| Hello Worldサイズ | 330KB | 100MB超 | 100MB超 | 100MB超 | 100MB超 |
| クロスコンパイル | ✅(iOS/Android/Web等) | ❌ | 限定的 | ❌ | 限定的 |
| Node.js API互換 | 部分的(主要pkg対応) | 高い | 一部 | ネイティブ | 一部 |
| React→ネイティブUI | ✅ | ❌ | ❌ | ❌ | ❌ |
| コンパイル言語 | Rust | Zig | Rust | C++ | Java |
| パッケージマネージャー | npm互換 | npm/yarn/pnpm | deno.land/x・npm | npm | Maven/Gradle |
Bunは「Node.js完全互換」を強みとし、既存のNode.jsコードをそのまま高速化するアプローチだ。一方Perryは互換性より「ネイティブバイナリ出力とクロスプラットフォーム」に重点を置く。どちらが適しているかはユースケース次第だ。
・配布バイナリが小さい必要があるCLIツール
・Node.jsランタイムを含めたくないサーバーレス環境
・TypeScriptでネイティブモバイルアプリを作りたい場合
・CPU集約的な計算でNode.js/Bunのパフォーマンスが不足している場合
・既存Node.jsコードを変更なく移植したい場合(互換性が不完全)
・動的eval()・Function()を多用するコード
・ネイティブアドオン(.node拡張)に依存するnpmパッケージ
・v0.5.x段階の破壊的変更を許容できないプロダクション環境
実際の使い方—インストールから動作確認まで
# macOSはHomebrewで
brew install perryts/perry/perry
# Linuxはワンライナーインストール
curl -fsSL https://raw.githubusercontent.com/PerryTS/perry/main/packaging/install.sh | sh
# 環境確認(Cリンカーの有無をチェック)
perry doctor
perry doctorコマンドで依存関係の確認ができる。エラーが出た場合は指示に従ってXcodeコマンドラインツール(macOS)やGCC/Clang(Linux)、MSVC(Windows)をインストールする。
プロジェクト作成からビルドまでの流れ:
# プロジェクト初期化
perry init my-app && cd my-app
# コンパイル
perry compile src/main.ts -o my-app
# コンパイル+実行をワンステップで
perry run .
# TypeScript互換性チェック(コンパイルなし)
perry check src/
perry checkコマンドは「このTypeScriptをPerryがコンパイルできるか」を事前に確認するためのツールだ。既存プロジェクトをPerryに移行する際の事前調査として活用できる。
ローカル環境からビルドするだけでモバイルアプリに
perry run iosを実行するとiOSシミュレーターでのビルド&実行が行われる。Xcodeのプロジェクトファイルを手動で管理する必要はなく、PerryがSwiftUIコードを生成してビルドパイプラインを処理する。
Androidもperry run androidで同様に動作し、Glanceコードが生成されてGradleビルドが走る。クロスプラットフォームフレームワークの中で、ここまでTypeScriptの記述量を変えずに複数プラットフォームへの展開を実現しているツールは多くない。
Perryのエコシステム—関連パッケージと実例
Perryには公式・コミュニティによるエコシステムが形成されつつある:
| パッケージ/プロジェクト | 内容 | 特徴 |
|---|---|---|
| Bloom Engine | TypeScript製ネイティブゲームエンジン | Metal/DirectX 12/Vulkan/OpenGL対応 |
| perry-react | React→ネイティブUIコンバーター | 標準Reactコンポーネントをそのまま利用 |
| perry-sqlite | SQLiteクライアント(Prisma互換API) | findMany・create・$transaction等 |
| perry-postgres | PostgreSQLクライアント(Prisma互換) | sqlxベース |
| perry-prisma | MySQLクライアント(Prisma互換) | |
| perry-apn | Apple Push Notifications | APNsネイティブ実装 |
| @perryts/threads | Webワーカー並列処理 | parallelMap・parallelFilter・spawn |
| Mango | ネイティブMongoDBクライアント | 7MB、<100MB RAM、サブ秒起動 |
| Hone | AI搭載ネイティブコードエディタ | macOS/Windows/Linux/iOS/Android |
Prisma互換APIでSQLite/PostgreSQL/MySQLを扱えるライブラリが揃っているのは実用上大きい。PrismaのAPIに慣れたTypeScriptエンジニアが、同じコードのまま(またはほぼ同じまま)Perry向けのネイティブアプリに移行できる可能性がある。
@perryts/threadsパッケージによるワーカースレッド並列処理は、TypeScriptで重い計算を並列化したいユースケースに対応する。parallelMap・parallelFilter・spawnといった高レベルAPIで並列処理を記述でき、内部ではRustのスレッドとメッセージパッシングが動いている。
ゲームエンジンのBloom Engineは、TypeScriptでゲームロジックを書きながらMetal(macOS/iOS)・DirectX 12(Windows)・Vulkan/OpenGL(Linux/Android)にコンパイルできる。3Dレンダリング・スケルタルアニメーション・空間オーディオ・物理演算を含み、TypeScriptゲームエンジンとしては最もネイティブ指向の設計だ。
まとめ—Perryが示す「TypeScript+Rust」の可能性
Perryが示す方向性は明確だ。TypeScript開発者がRustを書かなくてもRust級のパフォーマンスを得られる道を作ること。そのためにRust・SWC・LLVMという実績あるコンポーネントを組み合わせ、TypeScriptのコード資産を最大限に活用しながらネイティブアプリ開発を可能にする。
v0.5.17時点ではまだ発展途上で、TypeScriptとの完全な互換性はない。動的eval・全てのnpmパッケージ・高度な動的機能には制約がある。プロダクション投入には公式のtypescript-parity-gaps.mdを確認し、使用するAPIが対応済みかを事前に確認することが必須だ。
それでも、Perryが実証したことは重要だ。TypeScriptからネイティブバイナリを生成するアプローチで、Node.jsを最大38倍上回るパフォーマンスが出る。iOS・Android・Webへの1コードベース展開が実現できる。330KBのHello Worldバイナリが現実的に作れる。これらの数字は、TypeScriptをネイティブ開発の主要言語として使う可能性が技術的には成立することを示している。
関連記事: