TypeScript

PerryというTypeScriptネイティブコンパイラの基本概念と特徴

目次

PerryというTypeScriptネイティブコンパイラの基本概念と特徴

PerryはTypeScriptをそのままの構文で記述しながら、実行可能なネイティブバイナリへ直接変換できるコンパイラです。Node.jsやElectronといったランタイムを介さず、AppleのAppKitやLinuxのGTK4といった本物のOSウィジェットを利用したアプリケーションを構築できる点に特徴があります。本章では、Perryの技術的な位置づけや無ランタイム設計の意義、軽量バイナリと起動性能、内部のコンパイルパイプライン、そして既存npmエコシステムとの互換性について整理していきます。

PerryがTypeScriptを直接機械語へ変換する技術的位置づけ

Perryは、TypeScriptソースコードを中間的なJavaScriptを経由せずに、直接ネイティブの機械語へ変換するコンパイラとして設計されています。従来のNode.jsやBunが「JavaScriptランタイム上でTypeScriptを実行する」アプローチを採るのに対し、PerryはRustで実装されたコンパイラ本体がSWCで構文解析を行い、LLVMで最終的な機械命令を生成する設計です。JITウォームアップやインタプリタ層のオーバーヘッドが原理的に存在しない構造となっており、生成物は単独実行可能ファイルとして配布できます。

この位置づけにより、TypeScriptはWebフロントエンドやサーバサイドの言語という枠を超え、SwiftやRustと並ぶ「コンパイル型の汎用ネイティブ言語」として扱える対象へ広がります。型システムや構文をTypeScriptのまま維持しながら、生成バイナリはHello World相当で約330KB、stdlibを使うアプリでは48MB前後まで幅を持つ点が、他のクロスプラットフォーム技術と一線を画す技術的な特徴です。

Node.jsもV8もElectronも使わない無ランタイム設計の意義

Perryの最大の設計思想は、配布物に追加のランタイムを一切含めない点にあります。Electronアプリは内部にChromiumとNode.jsを抱え込むため、空のテンプレートでも100MBを超えることが珍しくありません。Perryで生成したバイナリはV8もNode.jsもJVMも持たず、必要なランタイム機能のみがリンクされた自己完結型の実行ファイルとして出力されます。この構造により、配布サイズの削減だけでなく、起動時のメモリ確保やGCのウォームアップに関連する遅延も回避できます。

無ランタイム設計のもう一つの意義は、セキュリティ面と運用面のシンプルさにあります。実行時にスクリプトをロードして評価する仕組みを持たない以上、一般的なJSランタイム特有の脆弱性経路を構造的に排除できる設計です。CI環境で生成したバイナリをそのままユーザのマシンへ配布できるため、ランタイムのバージョン依存に悩まされる場面も減らせる点が運用上の利点となります。

約330KBから始まる小型バイナリと0msコールドスタート性能

Perryで生成されるバイナリは、依存を持たないHello World相当のプログラムであれば約330KBという小ささに収まります。これは、コンパイラがプログラム内で実際に使用しているランタイム機能のみを検出し、必要な部品だけを最終バイナリへリンクする仕組みによる成果です。fsやpath、processなどstdlibの一部だけを使うレベルなら約380KB、fastifyやmysql2を含む本格的なサーバアプリでは約48MBまで段階的に増える特性が、READMEのBinary Size表で公開されています。

起動性能については、JITコンパイラのウォームアップを待つ必要がないため、コールドスタート時に発生する遅延がほぼ無視できる水準まで短縮されます。GUIアプリの起動瞬時のレスポンスや、CLIツールの初回呼び出し時の体感速度に大きな差をもたらす要素となり、ユーザ体験を直接的に押し上げる性能特性として注目される部分です。スクリプト型アプリと比べて、メモリ常駐量が少ない点も日常使いのユーティリティで利点として現れやすい特徴です。

Rust製コンパイラとSWC・LLVMによる処理パイプラインの基本

Perryのコンパイラ本体は、Rust言語で実装されたモジュール群から構成されています。TypeScriptの構文解析にはSWCが採用されており、最新の言語仕様にも追随しやすい設計が特徴です。中間表現としてHIRと呼ばれる独自データ構造を経由したのち、LLVMのバックエンドが各プラットフォーム向けの機械命令を生成するという段階的な処理パイプラインが構築されています。

このパイプラインにより、TypeScriptの型情報や非同期処理を、ネイティブコードの最適化に活かせる構造となります。具体的には、エスケープ解析によるオブジェクトの非ヒープ化、配列アクセスにおけるi32ループカウンタの利用、整数剰余の高速パスへの置換などが既定で適用されます。コンパイラとリンカが連動して、システムリンカが最終バイナリをまとめ上げる流れが、Perryの基本的な内部処理として把握しておくべき部分です。Rust製であることはビルド速度や安定性にも寄与しており、開発時の試行回数を確保しやすい点もメリットの一つです。

TypeScript厳密モード対応と既存npmエコシステムとの互換性の現状

Perryは、TypeScriptのstrictモードを前提とした型チェックを行いながらコンパイルできる構造を採用しています。クラスやジェネリクス、async/awaitといった主要な言語機能に対応し、型エイリアスや判別共用体なども扱える設計です。既存のTypeScriptプロジェクトを大きく書き換えずに、Perryへ移行しやすくする狙いが反映された方針となっています。

npmエコシステムとの互換性については、人気のあるNode.jsモジュールをRustで再実装したものをPerryのstdlibとして提供する方式が取られています。fastify、mysql2、ioredisといったライブラリを利用したサーバアプリケーションの動作例がPerryTS/perry-examplesリポジトリで公開されており、必要に応じて--enable-js-runtimeオプションでV8互換ランタイムを組み合わせることで、ピュアJSのnpmパッケージも扱える設計です。すべてのnpmパッケージがそのまま動くわけではない点は留意が必要であり、対応状況の確認が運用上の判断基準となります。

SWCとLLVMを組み合わせたネイティブコード生成の内部仕組み

Perryが「TypeScriptをネイティブのまま動かす」という体験を成立させているのは、SWCとLLVMを連動させた精緻なコード生成パイプラインの存在によるものです。本章では、SWCによる解析段階から最適化パス、LLVMバックエンドでの命令出力、ランタイム実装の選定基準、そしてf64演算における既定モードの設計まで、内部処理の流れを順を追って整理していきます。

SWCによるTypeScript構文解析と型情報の取り扱い手法

Perryの最初の工程は、Rust製の高速TypeScriptパーサであるSWCを用いた構文解析です。SWCはトークナイザから抽象構文木の生成までを高い処理速度で実行し、結果として得られたASTがPerry独自のHIR、つまり高水準中間表現へ変換されていきます。この段階で、TypeScript固有の型注釈や型エイリアス、ジェネリクスの情報が解析対象として取り込まれます。

型情報の取り扱いに関しては、単なる構文チェックの材料に留まらず、後続の最適化判断にも活用される設計となっています。READMEのCompiler Optimizationsセクションには、判別共用体や型ガードによって関数戻り値が数値型に確定する場合、不要なjs_number_coerce呼び出しを除去する最適化が明記されています。型情報がコンパイル後の機械命令の品質に直結する点が、Perryにおける構文解析段階の独自性として挙げられる部分です。SWCはRustエコシステムで標準的に利用されている高速パーサであり、最新のTypeScript構文への追随性が高い点も、Perryが採用するうえでの実務的なメリットとして機能しています。

HIRおよびIR変換段階で実施される最適化パスの具体例と適用効果

HIRからLLVM IRへ変換される過程では、Perryが独自に実装する複数の最適化パスが順番に適用されます。クロージャ変換やasync変換、関数のインライン化といった汎用的なパスに加え、TypeScriptとネイティブコードの橋渡しに特化した独自パスが組み合わさって、最終的なIRの品質を高める仕組みが構築されています。

  • 非エスケープオブジェクトのスカラー置換によるヒープ確保の排除
  • エスケープするオブジェクト向けのインラインバンプアロケータ
  • 境界が確定した配列アクセスへのi32ループカウンタの適用
  • 整数剰余の高速パス化(fptosi → srem → sitofpへの置換)
  • 純粋な数値再帰関数におけるi64特殊化

これらの最適化はPerryの既定モードで自動的に適用され、整数中心の演算や軽量な構造体操作を多用するコードに対して、Node.jsよりも有意に高速な実行性能を引き出す効果が確認されています。README掲載のベンチマーク表ではfactorialで約19倍(31ms対596ms)、closureで約30倍(10ms対309ms)といった大幅な高速化が報告されている点が代表例です。

LLVMバックエンド経由のネイティブコード生成と機械命令の出力

最適化済みのIRはLLVMバックエンドへ引き渡され、各ターゲットプラットフォームに対応した機械命令へ変換されます。LLVMは長年の実績を持つコンパイラ基盤であり、ARM64やx86_64といった主要なCPUアーキテクチャ向けに高度に最適化された命令列を生成できる設計が、Perryの性能を支える土台となっています。

生成された機械命令は、システムリンカによって標準ライブラリやプラットフォーム固有のAPIと結合され、自己完結型の実行ファイルとして書き出されます。macOSのAppKitやLinuxのGTK4といったGUI APIに対する関数呼び出しも、最終バイナリ内部では直接的なネイティブ関数呼び出しとして表現されるため、IPC境界やブリッジ層を通過するコストが発生しない構造です。LLVMによる強力な最適化と、ネイティブAPIへのダイレクトな結合の組み合わせが、Perryの実行性能を特徴づける本質的な要素として位置づけられます。

NaN-boxingやGC方式などランタイム実装の技術的な選定基準

Perryのランタイムは、TypeScriptの動的な値表現とネイティブコードの効率を両立させるために、複数の技術的選択を組み合わせた設計です。値の表現にはNaN-boxingが採用されており、IEEE754のf64で表せないビットパターンを利用して数値以外の値を1ワードに格納する手法が用いられています。これによりレジスタ受け渡しのコストが抑えられ、ホットパスにおける命令数の削減につながります。

メモリ管理については、READMEのRuntime CharacteristicsとCompiler Optimizationsで明記されているとおり、Mark-Sweep GC・アリーナアロケータ・インラインバンプアロケータが状況に応じて使い分けられる設計です。短命なオブジェクトはアリーナで素早く確保され、エスケープ解析によりレジスタやスタックに置けるオブジェクトはそもそもヒープ外で処理されます。これらの選定は、TypeScriptプログラムが想定する記述スタイルに対して、ネイティブコードとして妥当な実行コストを与えるという基準で決定されている点が特徴です。設計判断の積み重ねが、ランタイム全体の実装品質を支える土台となっています。

f64演算でNode.jsとビット一致を実現する既定モードの設計思想

浮動小数点演算の取り扱いは、ネイティブコンパイラの設計においてしばしば論点となる部分です。READMEのPerformance注記によれば、Perryはv0.5.585以降で既定モードが見直されており、f64演算の結果がNode.jsとビット単位で一致するように動作する設計が選択されています。これは、各命令にreassocやcontractといったfast-math flagsを発行しない既定動作によって実現されており、移植性と数値再現性を重視する判断が反映された方針です。

パフォーマンス最優先の用途向けには、明示的にfast-mathを有効化するオプトイン手段も用意されています。CLI引数として--fast-mathを渡すか、環境変数PERRY_FAST_MATH=1を設定するか、package.jsonに"perry": { "fastMath": true }を記述する3通りの方法が公式に提供されている仕様です。fast-mathを有効にすると、ベクトル化やFMA融合などのアグレッシブな最適化が解禁される一方、Node.jsとの数値ビット一致は保証されなくなる点が、利用判断の分かれ目となります。

対応10プラットフォームとネイティブUIフレームワーク連携の全体像

Perryの強みのひとつが、単一のTypeScriptコードベースから多数のプラットフォーム向けバイナリを生成できる点にあります。READMEのNative UI節には「10 target outputs from one codebase」と明記されており、デスクトップ・モバイル・ウェアラブル・テレビ・Webにまたがる広範な対応範囲が公式の特徴です。本章では、Apple系・Linux/Windows系・Android・Web系・ウェアラブル系という観点から、それぞれの連携構造と利用するネイティブUIフレームワークを整理します。

macOSのAppKitとiOSのUIKitに対応するApple系プラットフォーム

Apple系のプラットフォーム対応では、macOS向けにAppKit、iOS向けにUIKitが採用されています。これらはAppleが提供する標準的なネイティブUIフレームワークであり、SwiftやObjective-Cで開発されるアプリと同じウィジェットを利用できる構造です。Perryでビルドしたアプリは、ウィンドウ・ボタン・テキストフィールドなどがすべてAppKitやUIKitの実装としてレンダリングされ、システム全体のテーマやアクセシビリティ設定にも自然に追随します。

iOSとmacOSのApp Store配布も射程に入っており、SwiftUIをコード生成のターゲットにする経路も整備されています。READMEのプロジェクト構成にはperry-codegen-swiftuiというクレートがリポジトリに含まれており、iOSやwatchOS向けのウィジェットを生成する機構が組み込まれた設計です。実例としてPryというJSONビューアーが、AppleのApp Storeで実際に公開されている点が、Apple系での動作実績として確認できる材料となります。

GTK4とWin32を介したLinuxおよびWindowsデスクトップ対応の構造

デスクトップLinuxにおけるUIレンダリングには、GTK4が採用されています。GTK4はGNOMEを中心に広く利用されているウィジェットツールキットであり、Perryで生成されたアプリはWebViewを介さずにGTK4のネイティブ部品として描画されます。GTK4を呼び出すための開発用ライブラリを必要とするため、ビルド環境にはgtk4-develに相当するパッケージのインストールが前提条件となる点が実務的なポイントです。

Windows向けには、Win32 APIを利用した経路が用意されており、READMEのSupported platforms表ではWindowsバックエンドがWin32としてFullステータスで記載されています。Win32経由で生成されたバイナリはWindowsの標準ウィジェットを直接利用する形で動作する設計です。Windows版に関しては、perry-pryリポジトリの記載によればコード署名対応が「signing coming soon」と公式に明示されている段階のため、ストア配布や企業展開を行う際はその点を確認したうえで導入判断を行う流れが現実的です。

AndroidのJNI連携とAndroid Views描画によるモバイル対応の仕組み

Android向けの対応では、JNIを利用したネイティブ層と、Android標準のViewシステムを介したUIレンダリングが組み合わされています。具体的には、Perryコンパイラがビルド時に共有ライブラリ形式のネイティブコードを生成し、それを通常のAndroid Studioプロジェクトに組み込んで配布するフローが採用されています。共有ライブラリのファイル名はlibpry.soのような形式となり、ARM64向けのjniLibsディレクトリへ配置するのが標準的な構成です。

UIに関してはAndroid Viewsを直接操作する設計のため、ReactNativeのようなJSスレッドとUIスレッドの間のブリッジ通信を経由しません。AndroidのライフサイクルやIntentの仕組みもネイティブAPIへの呼び出しとして表現されるため、結果として消費メモリや起動時間の点で有利な構造が得られます。Pryに代表される実例では、Google Play Storeを通じたモバイルアプリ配布の実績も公開されています。

WebAssemblyとJavaScriptターゲットによるブラウザ展開の選択肢

Perryはネイティブ専用のコンパイラというわけではなく、Webへの展開も射程に含めた設計が採用されています。READMEのプロジェクト構成にはperry-codegen-jsとperry-codegen-wasmという2つのモジュールが組み込まれており、同一のTypeScriptコードからJavaScriptバンドルとWebAssemblyバイナリの両方を生成できる構造です。これにより、デスクトップ・モバイル向けのバイナリと並行して、Webブラウザで動作する版を同じコードベースから派生させられます。

Web向けに生成されたコードは、ネイティブUIではなくDOMウィジェットを介して描画される設計です。同じTypeScriptで記述したアプリを、ネイティブ版とWeb版の両方で展開したい場合、--target webでJavaScript出力、--target wasmでWebAssembly出力を指定するだけで両方のビルドを派生させられる利便性があります。Webビューをネイティブアプリ内に埋め込む構成とは根本的に異なり、対象環境に応じて最適な実行形態を選べる点が、ブラウザ展開における大きな選択肢となります。

watchOSとtvOSを含む10プラットフォーム横断対応の一覧整理

Perryが公式READMEの「10 target outputs from one codebase」でうたう対応プラットフォームは、デスクトップとモバイルに加え、ウェアラブルやテレビ、ブラウザを含む多岐にわたる広がりを持っています。watchOS向けにはWatchKit、tvOS向けにはUIKitの生成経路が用意されており、visionOSにも2DウィンドウとしてのUIKit対応が組み込まれた設計です。

プラットフォーム バックエンド ターゲットフラグ
macOS AppKit (NSView) (macOS既定)
iOS / iPadOS UIKit –target ios / ios-simulator
visionOS UIKit (2Dウィンドウ) –target visionos / visionos-simulator
tvOS UIKit –target tvos / tvos-simulator
watchOS WatchKit –target watchos / watchos-simulator
Android Android Views (JNI) –target android
Windows Win32 (Windows既定)
Linux GTK4 (Linux既定)
Web DOM (JSコード生成) –target web
WebAssembly DOM (WASM) –target wasm

これら10プラットフォーム横断の対応により、ひとつのTypeScriptコードベースを起点として、ユーザの利用環境に応じた配布チャネルを段階的に拡張していく開発戦略が取りやすくなります。当初はmacOS向けのみで提供を開始し、後からiOSやAndroidへ展開していくといったロードマップを採用しても、コード資産を活かしやすい設計となっている点がPerryの全体像として把握しておくべき要素です。

ElectronやReact NativeなどWebView系技術との構造的差異

Perryを評価するうえで避けて通れないのが、既存のクロスプラットフォーム技術との構造的な違いの把握です。本章では、Electronのバイナリ肥大化とPerryの軽量バイナリの違い、React Nativeのブリッジ通信との比較、TauriやFlutterとの描画方式の違い、そしてサイズや起動性能の比較表を通じて、Perryが立っているポジションを明確にしていきます。

Electronが抱えるバイナリ肥大化と起動遅延の課題に対する解

Electronは、ChromiumとNode.jsを実行ファイルに同梱することで、Webフロントエンドの技術スタックをそのままデスクトップアプリへ転用できる利便性を生み出した一方、配布バイナリの肥大化という構造的な課題を抱えています。Hello World相当のテンプレートでも100MB以上の容量となり、ユーザのインストール時間やストレージ占有量が無視できない要素になります。さらに、起動時にChromiumとV8のセットアップを伴うため、コールドスタートの遅延も体感されやすい部分です。

Perryは、ChromiumもV8も同梱しないという選択により、これらの課題に対する直接的な解を提供する設計です。バイナリはHello Worldで約330KBから、stdlibを使うアプリで約48MBまでの範囲に収まり、起動時のJavaScriptランタイムウォームアップが不要となるため、ダウンロード完了からアプリ起動までの体験全体が短縮されます。Webの技術スタックの再利用性をある程度妥協しても構わないと判断できる用途では、Electronの代替候補として位置づけられる選択肢となります。

React Nativeのブリッジ通信とPerry直接コンパイルの根本的な差

React Nativeは、JSで記述されたUIロジックをJavaScriptCoreなどのJSランタイム上で実行し、ネイティブUIスレッドとの間でブリッジ通信を行うことで描画やイベント処理を実現する設計です。新アーキテクチャによる改善は進んでいますが、JSスレッドとUIスレッドという2つの世界をブリッジで結ぶ構造そのものは保たれており、レンダリングのタイミングやイベント応答性に影響を及ぼす要素となっています。

これに対してPerryは、TypeScriptをネイティブコードへコンパイルすることで、JSスレッドという概念そのものを排除した直接コンパイル方式を採用しています。UIへの操作はネイティブ関数呼び出しとして直接表現され、ブリッジを経由しません。結果として、JSとネイティブの間の通信オーバーヘッドや、ブリッジ越しに大きなオブジェクトを渡す際のシリアライズコストが、構造的に発生しない設計となっています。両者の差は単なる性能の違いではなく、アーキテクチャの根本に関わる選択である点を理解しておくことが重要です。

Tauriが利用するWebViewレンダリングとPerry描画方式の違い

Tauriは、Electronと同じくフロントエンドの技術をデスクトップアプリへ転用する流れを汲みつつ、各OS標準のWebViewを利用することで配布サイズを抑えるアプローチを取っています。バックエンドにはRustを採用し、フロントエンドはWebView上で描画されるため、ChromiumとNode.jsを同梱するElectronと比較してバイナリは大きく軽量化される傾向です。

ただし、Tauriの描画方式は本質的にWebViewへ依存するため、UIの見た目はOS標準のWebViewレンダリング結果となり、ピクセル単位で完全にネイティブな見た目とは異なる部分があります。一方Perryは、AppKitやGTK4といった本物のOSウィジェットを利用するため、メニュー・ボタン・スクロールビューといった要素がOS標準と同一の挙動と外観で描画される構造です。WebViewベースの軽量化を選ぶか、ネイティブウィジェットによる本物の挙動を選ぶかは、用途とユーザ体験への要求水準に応じた判断ポイントとなります。

Flutterの独自レンダリングエンジンと比較した際のUI実装方針

Flutterは、Skiaなどの独自レンダリングエンジンによって、すべてのプラットフォーム上でピクセル単位で同一のUIを描画するアプローチを取っています。これにより一貫したブランド体験を実現できる反面、各OSのデザインガイドラインに沿った見た目を完全に再現しづらいというトレードオフが生じます。Material DesignやCupertinoといったテーマウィジェットでカバーできる部分も多いものの、最終的には独自エンジンが描いている点に変わりはありません。

Perryの実装方針は対極にあり、各プラットフォームのネイティブUIフレームワーク、つまりAppKit・UIKit・GTK4・Win32・Android Viewsを直接呼び出してUIを構築する設計です。OS標準のスクロール挙動・コンテキストメニュー・アクセシビリティといった細部まで、各プラットフォーム本来の流儀がそのまま反映されます。一貫したブランド体験よりも、各OSの作法に沿った自然な使い心地を重視する設計判断において、Perryのアプローチが噛み合うケースが多いと整理できます。

各フレームワークとPerryのバイナリサイズおよび起動性能比較表

クロスプラットフォーム技術の選定では、配布サイズと起動時間が現実的な比較軸として頻繁に参照されます。Perryの公式情報や実例から得られる数値と、ElectronやTauriの一般的な傾向を整理すると、Perryが際立って軽量な部類に入ることが読み取れる傾向です。実際の数値はアプリの内容や依存ライブラリによって変動しますが、典型的なオーダー感を把握するうえで有用な比較となります。

技術 典型的なバイナリサイズ 主な描画方式 ランタイム同梱
Perry 約330KB〜48MB(用途依存) ネイティブUI(AppKit/GTK4等) なし
Electron 100MB前後〜 Chromiumレンダリング Chromium+Node.js
Tauri 10MB前後 OS標準WebView OS標準WebViewに依存
React Native アプリ依存(数十MB) ネイティブ+JSブリッジ JSランタイム
Flutter 10〜20MB前後 独自エンジン(Skia等) Dart/Flutterランタイム

サイズだけでなく、起動時のJITウォームアップの有無や、ランタイム同梱の必要性といった軸でも、Perryは「ランタイムなし・ネイティブUI・小型バイナリ」という独特なポジションを占めます。比較表は概算であり、実プロジェクトでは依存ライブラリや組み込むアセットにより値が変動する点を踏まえつつ、技術選定の方向性を判断する材料として活用するのが適切です。

SwiftUI風宣言型UIシステムとparallelMapによる並列処理機能

Perryには独自のUIシステムとスレッドモデルが組み込まれており、TypeScriptのまま宣言型UIや本物のOSスレッドを扱える設計が採用されています。本章では、VStackやHStackによるレイアウト構築、127を超えるUI関数の活用範囲、parallelMapやspawnによるマルチスレッド処理、コンパイル時の安全性検証、そしてCLDRに基づく国際化機能まで、Perryの機能面の中核を取り上げます。

VStackやHStackを使った宣言型レイアウト構築の実装パターン

Perryが提供するUIシステムは、SwiftUIに着想を得たスタックベースの宣言型レイアウトを採用しています。perry/uiモジュールからVStackやHStack、Text、Buttonなどのコンポーネントをインポートし、ネスト構造でレイアウトを記述するスタイルが基本パターンです。CSSやHTMLを介さず、配置ルールはアラインメントとディストリビューションで指定する設計のため、Webの世界とは異なるメンタルモデルでUIを構築することになります。

典型的な記述はimport { App, VStack, HStack, Text, Button, Spacer } from 'perry/ui';のような形でAPIを取り込み、関数呼び出しのネストでウィジェットツリーを組み上げる形になります。サイドバーとメインコンテンツを並べる構成にはSplitViewが、縦方向の積み上げにはVStack、横方向の並びにはHStackを使い分ける流れです。OSのテーマ設定やアクセシビリティ機能は、ネイティブウィジェットとして描画されるため自動的に追随します。これにより、TypeScriptのまま各OSの作法に沿ったUIを宣言的に記述する実装パターンが成立します。

ButtonやTextFieldなど127UI関数からなる標準ウィジェット群の活用範囲

Perryの公式READMEは、127にのぼるUI関数を提供することを明示しており、デスクトップアプリやモバイルアプリで一般的に必要とされる部品を網羅する範囲をカバーしています。これらすべてが各プラットフォームでネイティブの実装にマッピングされる設計のため、見た目と挙動の両面でOS標準と一致する体験を提供できる点が特徴です。

  • Button、Text、TextField、Toggle、Slider、Pickerといった基本入力部品
  • Table、Canvas、Image、ProgressView、SecureFieldなどの表示・描画系ウィジェット
  • NavigationStack、ZStack、LazyVStack、Form、Sectionといった構造化コンポーネント
  • キーチェーン、通知、ファイルダイアログ、クリップボードなどのシステムAPI
  • VStackやHStackといったSwiftUI風のレイアウトスタック

これらのウィジェットは、macOSのAppKit、iOSのUIKit、AndroidのAndroid Views(JNI連携)、WindowsのWin32、LinuxのGTK4へそれぞれマッピングされる構造となっています。プラットフォーム固有の挙動が必要な場面では、OSごとのエントリーポイントを別ファイルとして用意するパターンを取れる柔軟性も併せ持つ点が特徴です。Pry実装のmain.ts・main_ios.ts・main_linux.tsといったファイル分割が、その実例として参考になります。

parallelMapとparallelFilterによる本物のOSスレッド活用方法

Perryのもうひとつの特徴的な機能が、本物のOSスレッドを利用した並列処理APIです。READMEの「Multi-Threading」節にはperry/threadモジュールが掲載されており、配列の要素を並列に変換するparallelMap、並列にフィルタするparallelFilter、独立したワーカースレッドを起動するspawnが標準機能として提供される設計です。Workerによるメッセージパッシングや、SharedArrayBufferの取り扱いといったWebの並列処理の制約を意識する必要がありません。

典型的な記述としてはconst results = parallelMap([1, 2, 3, 4, 5], n => fibonacci(n));のように、通常のmapを置き換える感覚で利用できる設計です。バックエンドではOSのスレッドプールが活用され、各スレッドが独自のアリーナとGCを持つことで競合を避けつつCPUコア数に応じてスケールする並列実行が実現します。画像処理や大量データの集計など、CPUバウンドな処理を扱うアプリにおいて、TypeScriptのまま並列性を引き出せる点がPerryのユニークな立ち位置となります。

spawn関数によるスレッド生成とコンパイル時安全性の検証ルール

parallelMapやparallelFilterが宣言的な並列処理を提供する一方で、より低レベルなスレッド制御を必要とする場面のためにspawn関数が用意されています。const result = await spawn(() => expensiveComputation());のように記述することで、任意の関数を独立したOSスレッドとして起動し、Promise経由で結果を受け取れる仕組みです。Workerのようなメッセージシリアライズを介する必要がなく、ネイティブスレッドを直接活用できる点が特徴です。

同時にPerryは、共有メモリ並列性に伴うバグの混入を防ぐため、コンパイル時にmutableキャプチャを拒絶するというルールを設けています。READMEには「The compiler enforces that closures don’t capture mutable state」と明記されており、スレッド境界をまたいで可変参照を持ち込む記述はコンパイラが静的に検出してエラーとして扱う仕組みです。これにより、SharedArrayBufferやWorkerに関連する典型的な落とし穴を、ランタイムではなくコンパイル時点で予防する設計が実現しています。並列処理の利便性と安全性を両立する判断基準として、Perryらしい独自性が現れている部分と言えます。

CLDR複数形ルールに基づく30以上の言語対応と国際化機能の実装

国際化機能もPerryの標準機能として組み込まれている領域のひとつです。READMEの「Internationalization (i18n)」節には、CLDR(Common Locale Data Repository)の複数形ルールに準拠し、30を超えるロケールに対応した翻訳機構が用意されていると明記されています。perry/i18nモジュールから提供されるt()関数を使い、TypeScriptソース内に記述された文字列がビルド時に自動的に抽出され、複数形を含む翻訳テンプレートが生成される構造です。

この国際化システムの特徴は、翻訳データがバイナリ内部に焼き込まれる点にあります。READMEは「All locale strings are baked into the binary at compile time」と明示しており、実行時にi18nリソースを動的に読み込む処理が不要となるため、ロケール切替時のレスポンスが極めて速く、リソース読み込み失敗のリスクも構造的に発生しません。perry.tomldefault_localelocalesを記述するだけで多言語化を有効化でき、CurrencyやShortDateといったロケール対応のフォーマット関数も提供されている点が、Perryの国際化機能の包括性を示します。

macOSとLinuxにおけるインストールから初回コンパイルまでの手順

Perryを実際に試すための導入ハードルは、想像よりも低い水準に設計されています。本章では、macOSとLinuxを中心に、Homebrewやnpmによるインストール手順、gtk4-develなどの前提条件、初回のhello.tsコンパイル、ターゲット指定の方法、そしてストア公開を自動化するperry publishの利用までを順を追って解説していきます。

HomebrewによるmacOSへのPerryインストールと前提条件の確認

macOS環境では、Homebrewを利用したインストールが推奨される導入経路として案内されています。READMEの「Installation」セクションではbrew install perryts/perry/perryのコマンド一行でPerryを導入できる手順が示されており、Apple Silicon搭載機でもIntel Mac環境でも同一の手順でセットアップを開始できる点が利点です。前提条件としてXcode Command Line Tools(xcode-select --install)の導入が必要となるほか、npmやnpx経由のインストール、scoopやwingetによるWindows導入も並行して提供されている構成です。

インストール後は、perryコマンドがシェルから呼び出せる状態となり、コンパイルや初期化、ヘルスチェックといった基本操作がCLIから実行可能となります。CLIが提供する主要コマンドにはcompile、run、check、init、doctor、publishなどが含まれており、開発の入り口として必要な機能が一式揃った構成です。インストール直後にperry doctorを実行して、Rustツールチェーンやリンカ、各プラットフォームSDKの揃い具合を確認しておくと、その後の作業が円滑に進みます。

gtk4-develを必要とするLinux環境での開発準備と注意点

Linux環境においては、GTK4を利用するために開発用ヘッダパッケージのインストールが前提条件となります。FedoraやRHEL系であればgtk4-devel、Debian系であればlibgtk-4-devといったパッケージ名で提供されているため、ディストリビューションに応じたパッケージマネージャでの導入が必要です。これらが不足するとビルド時にリンクエラーが発生し、Perryのコンパイルが完了しない典型的な失敗パターンに該当します。

Linuxビルドを行う際の典型的な実行コマンドは、cargoでPerry本体をビルドしたうえでcargo run --release -- compile src/main_linux.ts -o pryのような形になります。注意点としては、デスクトップエントリやアイコンファイルの配置、Wayland/X11切り替えなど、Linux固有のデスクトップ統合作業は別途必要となる点が挙げられます。配布形式についてもAppImageやFlatpakといった選択肢があり、対象ユーザの利用環境に合わせた配布戦略の検討が、Linux対応における実務的なポイントです。

hello.tsから始める初回コンパイルとperryコマンドの基本構文

Perryの最初の体験は、シンプルなhello.tsをコンパイルしてバイナリを生成するところから始めます。console.log("Hello, world!")という1行のTypeScriptを書いておき、ターミナルでperry compile hello.ts -o helloを実行する流れです。これにより、helloという名前のネイティブバイナリが生成されます。実行は./helloで行え、メッセージが標準出力に表示される点を確認することで、環境セットアップの完了が判断できます。

  1. 任意のディレクトリにhello.tsを作成し、TypeScriptで処理を記述する
  2. perry compile hello.ts -o helloを実行してネイティブバイナリを生成する
  3. 生成された./helloを実行し、想定どおりの出力が得られるか確認する
  4. perry checkで型エラーや構文エラーの有無を事前にチェックする
  5. perry initでプロジェクトの雛形を作成し、本格的な開発へ移行する

これらの初期手順を一通り体験することで、PerryのCLIが提供する基本構文と開発フローが体得できます。compileサブコマンドには--print-hirでHIRを表示するオプションや、--enable-js-runtimeでV8互換ランタイムを埋め込むオプションも用意されており、検証段階で内部挙動を確認したい場面に活用できる仕様です。

macOS arm64とx86_64両方への対応とビルド時のターゲット指定

macOSではApple SiliconのARM64アーキテクチャと、従来のIntel Mac向けx86_64アーキテクチャの双方をサポートする必要があります。Perryはこれら両方のアーキテクチャ向けにバイナリを生成できる設計となっており、ビルド時のターゲット指定によって出力対象を切り替える仕様です。複数アーキテクチャ向けのバイナリを生成する際は、それぞれの環境でビルドする方法と、クロスコンパイルを利用する方法のどちらかを選ぶことになります。

iOSやAndroid、ウェアラブル向けのビルドでは、ターゲットフラグを明示的に指定する流れになります。READMEには--target ios-simulator--target ios--target android--target visionos--target tvos--target watchosといった多数のターゲットが明記されており、ホームスクリーンウィジェット向けの--target ios-widget--target wearos-tileまで網羅された設計です。Pryのようなマルチプラットフォーム対応アプリのビルドスクリプトでは、各プラットフォーム向けにビルドコマンドが個別に並べられており、CIで全プラットフォーム向けバイナリを並列生成する構成にしやすい設計となっています。リリース時のフラグ管理を整備しておくと、複数ターゲットへの定期ビルドが運用しやすくなります。

perry publishによるストア公開の自動化と署名処理の流れ

Perryには、ビルドしたバイナリをストアへ公開するまでの工程を支援するperry publishコマンドが用意されています。READMEの「Publishing」セクションにはperry publish macosのような形式が示されており、Apple App StoreやGoogle Play Storeへの提出、パッケージング、公証(notarization)といった作業を自動化する役割を担う仕組みです。perry-hubと呼ばれるクラウドビルドサーバへTypeScriptソースを送信し、各ターゲット向けにクロスコンパイルおよび署名を行う流れが採用されています。

App Storeへの公開を行う際は、Apple DeveloperアカウントのIDや証明書類をperry publishへ事前に登録しておき、コマンド一回でアーカイブ生成から提出までを進められる構造です。公証処理はAppleのサーバとのやり取りを伴うため完了までに時間がかかる場合があり、CI上で待機できる構成にしておくと運用が安定します。perry publishはオープンソースプロジェクト向けには無償提供される一方、チーム向けには有償プランが用意されている領域でもあるため、商用利用時には公式の/publishページで料金や条件を確認しておくことが推奨されます。

PryやdB Meter等の実例で見るバイナリサイズと起動速度の実態

Perryの真価は、公式の宣伝文句よりも、実際にPerryで構築されたアプリの数値や挙動から判断するのが現実的です。本章では、JSONビューアーのPry、データベースGUIアプリの事例、3プラットフォームに対応した天気アプリ、平均2.2倍の高速化を達成するベンチマーク結果、ゲームエンジンやAI搭載コードエディタといった事例集を順に取り上げ、バイナリサイズと起動速度の実態を具体的に整理していきます。

Pryが体現するJSONビューアーとしての軽量バイナリ実装の実態

Pryは、Perryコンパイラで構築された代表的なネイティブアプリのひとつであり、TypeScriptをARM64ネイティブコードへ直接コンパイルしたJSONビューアーとして公開されています。リポジトリの説明によれば、ツリーナビゲーション、検索機能、キーボードショートカットといった実用的な機能を備えた軽量アプリとして設計されており、JSONファイルを扱う日常的な開発作業の補助ツールとして活用できる位置づけです。

Pryの実装は、macOS・iOS・Android・Linux・Windowsの各プラットフォームに対応しており、それぞれのエントリーポイントが別々のmain_xxx.tsファイルに分かれた構造を取っています。コードベース全体は4つのエントリーポイントと11の共有モジュールで構成されているとされ、共通ロジックをTypeScriptで一元管理しつつ、UI層だけをプラットフォームごとに最適化する典型的なPerryアプリのファイル構成パターンが特徴です。Pryは実際にApple App StoreやGoogle Playで配布されており、ストア審査を通過した実績がある点も、軽量バイナリ実装の信頼性を示す材料となります。

約7MBで起動するMongoDB GUIアプリの低RAM消費の実測例

Perryで構築されたネイティブアプリの中には、MongoDB向けのGUIクライアントMangoも含まれています。READMEの「Built with Perry」テーブルでは、Mangoのバイナリサイズが約7MB、消費RAMが100MB未満、コールドスタートが1秒未満という具体的な数値が示されています。Electronで構築された一般的なデータベースGUIアプリと比べると、配布サイズと実行時メモリの両面で大きく抑えられた水準です。

このMongoDB GUIは、すべてTypeScriptで構築されている点が特筆すべき特徴です。データベースアプリケーションは通常、ネイティブドライバとの連携やUIの応答性が課題となりやすい領域ですが、Perryによってネイティブコードへ直接コンパイルされることで、起動の俊敏さとUIの即応性を両立する実装が成立しています。MangoはmacOS、Windows、Linux、iOS、Androidの5プラットフォームに対応した形で公開されており、データベース管理ツールのような頻繁に開閉される業務アプリにおいて、Perryのアプローチが特に効果を発揮する事例として参考になります。

60fps音圧計測dB Meterが示す3プラットフォーム共通アプリの実例

「Built with Perry」セクションには、リアルタイム音圧計測を行うdB Meterというアプリが掲載されています。READMEの記載によれば、毎秒60フレームの更新と端末ごとのキャリブレーション機能を備えたアプリで、iOS・macOS・Androidの3プラットフォームに対応するクロスプラットフォームの実例です。TypeScriptで記述したオーディオ計測ロジックがネイティブバイナリとして動作し、各プラットフォームのオーディオAPIへ直接アクセスする構成となっています。

dB Meterの存在は、リアルタイム性を要求されるオーディオ計測のような用途でもPerryが実用レベルで機能することを示す事例です。60fpsの波形表示やデバイスマイクからの連続入力処理がスクリプト言語のJITウォームアップを伴わずに実行できるため、ユーザの操作開始直後から正確な計測結果を提示できます。デスクトップとモバイルで同一のコードベースを共有しつつ、UI層のみをプラットフォームごとに切り替える設計を検討するうえでの参考になる事例としても活用できる位置づけです。

フィボナッチ等整数演算でNode.jsの2.1倍速を達成する性能特性

Perryの性能面に関しては、公式リポジトリのbenchmarksディレクトリで多数のベンチマーク結果が公開されています。READMEのPerformance表にはmacOS ARM64でNode.js v24と比較した10種類のベンチマーク結果が掲載されており、フィボナッチで2.1倍、math_intensiveで3.0倍、object_createで3.5倍、closureで4.5倍といった具体的な数値が並ぶ構成です。10ベンチマークの平均では2.2倍の高速化が確認されている点が、性能を評価するうえでの基準となります。

性能ベンチマークの結果は、計算の性質によって優位性が変動する点に留意が必要です。整数中心の再帰、オブジェクト確保、メソッド呼び出し、配列読み書きといった主要な観点でNode.jsを上回る結果が得られている一方、loop_overheadのように差が小さい項目もあります。性能評価を行う際は、用途に近い処理特性のベンチマークを参照し、必要に応じて自前で計測する姿勢が判断基準として欠かせません。READMEに含まれる./run_benchmarks.shを活用することで、自身の環境でベンチマークを再現できる仕様も整備されています。

ゲームエンジンやAI搭載コードエディタなど多様な実用アプリ事例集

Perryで構築された実用アプリの事例は、JSONビューアーやデータベースGUIにとどまりません。READMEの「Built with Perry」セクションには、より野心的なプロジェクトが多数掲載されており、TypeScriptで記述したアプリがネイティブバイナリとして実用レベルで動作する範囲の広さを示しています。これらの事例は、Perryを採用するかどうかの判断材料として非常に参考になります。

  • Bloom Engine: Metal・DirectX 12・Vulkan・OpenGLに対応したネイティブTypeScript製ゲームエンジン
  • 2D・3DレンダリングやスケルタルアニメーションをTypeScriptで記述するエンジン実装
  • Hone: ターミナル・Git・LSPを備えたAI搭載のネイティブコードエディタ
  • dB Meter: 60fps更新と端末別キャリブレーションを実現する音圧計測アプリ
  • 標準コンポーネントをネイティブウィジェットへコンパイルするperry-react実装

これらのプロジェクトは、いずれもPerryをベースに構築されており、ゲーム・開発ツール・計測アプリ・UIフレームワークといった多様な領域でTypeScriptがネイティブ実装の選択肢になり得ることを示しています。Bloom EngineはmacOS・Windows・Linux・iOS・tvOS・Androidという6プラットフォームに対応しており、HoneはWebを含む7環境で動作するなど、それぞれが対応プラットフォームの広がりを実証する事例です。事例集を参照することで、自身のプロジェクトにPerryを採用する際のスコープ感を具体的にイメージしやすくなる点が、判断段階での重要な情報源です。

Perry導入における適性判断・現状の制約・将来発展性の整理

最終章では、Perryを実プロジェクトへ採用するかどうかを判断するための観点を整理します。TypeScript経験者にとっての適性、バージョンv0.5系という現状の成熟度、Geisterhandを利用したUIテスト自動化、Windowsコード署名のような残存制約、Electronからの移行コスト試算という観点から、導入判断のための実務的なフレームを提示していきます。

TypeScript経験者が乗り換えを検討する際の適性判断3つの観点

TypeScriptの実務経験を持つ開発者にとって、Perryへの乗り換えを検討する場面では、3つの観点から適性を整理することが有効です。第一に、構築するアプリがネイティブUIの作法を必要とするか、それともWeb的なUIで十分かという点です。OS標準のメニューや右クリック動作、アクセシビリティが重要な業務系デスクトップアプリでは、Perryのネイティブウィジェットアプローチが適合しやすい傾向があります。

第二に、起動速度や配布サイズがユーザ体験に直結するかという点です。社内ツールであれば多少の起動遅延は許容される場合もありますが、消費者向けのモバイルアプリやポップアップ的に頻繁に起動するユーティリティでは、軽量バイナリと0msに近いコールドスタートが採用判断を後押しします。第三に、開発チームがTypeScript以外の言語(SwiftやKotlinなど)を学ぶ余力を持つかという点です。Perryなら学習負担を抑えつつ複数プラットフォームへ展開できるため、人的リソースが限られたチームほど判断が傾きやすくなります。

バージョンv0.5系で残るCLI機能と公式ドキュメントの成熟度

Perryは2026年5月時点でREADMEに「Current Version: 0.5.152」と表示されており、メジャーバージョンに到達していない発展途上のプロダクトです。GitHubスター数は約2.7k、フォーク数90、Issues48件と一定の利用者と開発活動を抱えており、v0.5.585での既定モード見直しのように細かな改善が継続的に投入されている状態です。公式ドキュメントは整備が進んでいるものの、APIの細部や設定オプションについては今後の変更可能性が残されている領域となります。

導入判断にあたっては、現時点でのドキュメント・サンプル・GitHub上のperry-examplesリポジトリを実際に確認し、想定する用途に必要な機能が現在の成熟度で満たされているかを精査する姿勢が重要です。CLIにはcompile・run・check・init・doctor・publishといった主要コマンドが揃っており、いずれも実際に利用可能な状態で提供されています。express-postgres、fastify-redis-mysql、hono-mongodb、nestjs-typeorm、nextjs-prisma、koa-redisといった代表的なNode.jsスタックの動作例も公開されているため、サーバ用途での適合性を実プロジェクトの構成に近い形で検証できる点は判断材料となります。バージョンが上がるにつれてAPIが安定していくことが想定されるため、長期運用を前提とする商用プロジェクトでは、その点を加味したロードマップ設計が現実的です。

Geisterhandを活用したUIテスト自動化と6プラットフォーム検証

Perryには、Geisterhandと呼ばれるインプロセスのUIテストフレームワークが組み込まれています。READMEの「Testing (Geisterhand)」セクションに記載されているとおり、HTTP経由でアプリのUIを操作し、スクリーンショットを取得しながら全プラットフォームでの動作を検証する仕組みです。perry compile src/main.ts --enable-geisterhand -o myappのようにビルド時にフラグを有効化すると、実行時にローカルポート(7676)でテストサーバが立ち上がる構造となっています。

このフレームワークの強みは、READMEで「Supports screenshot capture on all native platforms」と明記されているとおり、ネイティブプラットフォーム横断でスクリーンショットキャプチャを伴う自動化UIテストが実行可能とされている点にあります。CI上で同じシナリオを各プラットフォーム向けバイナリに対して走らせることで、特定プラットフォームのみで発生するレイアウト崩れや挙動の違いを早期に検出できる構造です。テスト自動化のカバレッジが品質保証の判断基準となる業務アプリにおいて、Geisterhandの存在は導入判断を後押しする実務的な要素として位置づけられます。

Windowsコード署名待ちなど2026年現在で残る本番運用上の制約

Perryを本番運用へ投入する際に留意すべき制約として、いくつかの未対応項目が公式に開示されています。代表的な例がWindows版のコード署名であり、リポジトリの記載によれば執筆時点で「signing coming soon」というステータスです。Windows DefenderのSmartScreenによる警告を回避するためには署名が事実上必須となるため、Windows向けに広範に配布するアプリではこの点が現実的な制約となる場面があります。

そのほかにも、すべてのnpmパッケージがそのまま動作するわけではない点、APIが安定するまでに細かな破壊的変更が入る可能性がある点、エコシステム全体の規模がNode.jsやReact Nativeと比べると新興である点などが、本番運用上の制約として挙げられます。一方で、ストア配布まで実現しているPryのような実例も増えつつあり、用途次第では現時点でも十分な実用性が確保できる状況です。導入の意思決定では、対象プラットフォームとアプリの性質に照らして、これらの制約が許容範囲に収まるかを冷静に評価する姿勢が求められます。

Electronから移行する際に検討すべき具体的なコスト試算ポイント

既存のElectronアプリをPerryへ移行する際は、いくつかの具体的なコスト要素を試算しておくことが大切です。第一に、UI層の書き換えコストが挙げられます。Electronアプリのフロントエンドは多くの場合HTML/CSS/JSで構築されているため、Perryの宣言型UIへ書き換える作業は単純な移植では済まず、UIの再設計に近い工数が想定される領域です。

第二に、利用しているnpmパッケージの代替可否の調査が必要です。Perry付属のstdlibでカバーされる範囲、ピュアJSパッケージとして--enable-js-runtimeとcompilePackages設定で動作する範囲、ネイティブモジュールに依存しているため代替実装が必要な範囲という3つの分類で精査するアプローチが有効です。第三に、配布チャネルとCI/CDの再構築コストも見落とせない要素となります。Electron Builderなどのツールから、perry publishを中心としたフローへ切り替える際の作業量を見積もったうえで、移行後に得られる起動速度向上と配布サイズ削減のメリットと比較する流れが、判断段階での具体的なコスト試算ポイントです。

資料請求

RELATED POSTS 関連記事