---
title: "Perryとは？TypeScriptをネイティブバイナリへ直接コンパイルする仕組みと実測【v0.5.1520】"
url: "https://www.issoh.co.jp/tech/details/12041/"
published: 2026-05-09
updated: 2026-10-08
categories: ["TypeScript"]
publisher: "株式会社一創"
---

# Perryとは？TypeScriptをネイティブバイナリへ直接コンパイルする仕組みと実測【v0.5.1520】

Perry（PerryTS）は、TypeScriptのソースをSWCで解析し、LLVMで機械語に変換して単体の実行ファイルを出力するRust製のコンパイラです。標準のビルドではNode.jsやJavaScriptエンジンを同梱せず、macOS・Windows・Linuxに加えてiOS・Android・watchOSのアプリも同じコードから生成します。リポジトリ（[PerryTS/perry](https://github.com/PerryTS/perry)）は2026年1月19日に作成され、2026年10月8日時点のスター数は4,942（GitHub API）、ライセンスはMITです。

本記事では、最新リリースのv0.5.1520（2026年9月11日公開）をIntel Mac（x86\_64）に入れて計測したバイナリサイズと起動時間、公式ドキュメントに書かれた言語機能の制限、ElectronやTauriと比べたときの採用判断をまとめます。

## まとめ：Perryの用途と採用前の制約

- Perryは `perry compile main.ts -o app` でTypeScriptを機械語の実行ファイルにする事前（AOT）コンパイラ。実行時にJavaScriptエンジンを持たない
- インストールは `npm install -g @perryts/perry`、Homebrew、wingetのいずれか。リンクのためにXcode Command Line Tools、gcc／clang、WindowsではLLVMが別途必要
- Intel Macでの実測は、hello worldが14.3MB、起動が中央値32.9ms（Node.js v26.5.0は253.2ms）。公称の「約330KB」は、ソースツリーを使ったサイズ最適化ビルドが前提
- 実行時に組み立てた文字列の `eval` は、既定ではビルドが通り実行時に例外になる。`--strict-eval` でコンパイルエラーにできる
- `parallelMap` などで外側の変数に書き込むコードはコンパイルが拒否される。並列処理の結果は戻り値で集める
- 版は0.5系で、GitHub Releasesは2026年10月8日時点で累計159件。社内CLIや小さなデスクトップツールで試し、ストア配信アプリの主力にするのは待つのが妥当

## Perryの仕組み：SWCで解析しLLVMで機械語を出す流れ

公式ドキュメントの[Hello Worldの章](https://perryts.github.io/perry/getting-started/hello-world.html)は、`perry file.ts -o output` を実行したときの処理を5段階で説明しています。SWCでTypeScriptを構文解析し、HIR（高水準の中間表現）に落とし、インライン化やクロージャ変換などの最適化をかけ、LLVMで機械語を生成し、最後にシステムのCコンパイラ（リンカ）で実行ファイルにまとめる流れです。v0.5.1520ではLLVM 22をコンパイラ本体に組み込んでおり、手元のビルドログにも `in-process LLVM backend active (LLVM 22.1.8)` と出ました。構文解析を担うSWCそのものの設定や用途は[SWCとは？Rust製コンパイラの設定と採用判断を実装目線で解説](/tech/details/16019/)で扱っています。

Node.jsやBunとの違いは、配布物の中身にあります。READMEの比較表は次のように整理しています。

| 項目     | Perry                     | Node.js         | Bun             | Electron       |
| ------ | ------------------------- | --------------- | --------------- | -------------- |
| 配布するもの | ネイティブバイナリ1本               | コード＋Node.js本体   | JSエンジン内蔵のバイナリ1本 | ブラウザエンジン入りのアプリ |
| 実行方式   | 事前コンパイルの機械語               | JIT             | JIT             | JIT            |
| UI     | AppKit・UIKit・Win32・GTK4など | なし              | なし              | Chromium       |
| 並列処理   | OSスレッド                    | worker\_threads | Worker          | プロセス           |

名前が似ている技術との混同にも注意が必要です。[TypeScript 7とは？Go製ネイティブコンパイラtsgoで最大10倍高速化｜RC公開と移行の要点【2026年最新】](/tech/details/10175/)の「ネイティブ」は型検査器（tsc）をGoで書き直したという意味で、出力は従来どおりJavaScriptです。PerryはTypeScriptから直接機械語を出す点で別物です。同じく機械語を狙うがC言語を経由する方式は[scriptcとは？TypeScriptをC経由でネイティブ化する仕組みと採用条件](/tech/details/16379/)で比較できます。

## インストールから初回コンパイルまでの手順

### npm・Homebrew・wingetでの導入と前提ツール

[README](https://github.com/PerryTS/perry)が案内するインストール方法は3通りです。npm版はOSとCPUに合ったビルド済みバイナリを `optionalDependencies` で取り込む薄いランチャーで、Node.js 16以上が要ります。

```
# どれか1つ
npm install -g @perryts/perry
brew install perryts/perry/perry
winget install PerryTS.Perry

# 環境の確認（リンカやプラットフォーム用ツールの有無）
perry doctor
```

Perryは最後のリンクをOSのツールチェーンに任せるため、本体とは別に次の準備が必要です（[インストール手順のドキュメント](https://perryts.github.io/perry/getting-started/installation.html)より）。

- macOS：Xcode Command Line Tools（`xcode-select --install`）
- Linux：gccまたはclang。Debian／Ubuntuなら `build-essential`。glibc版の配布バイナリはglibc 2.31以上（Ubuntu 20.04以降、Debian 11以降など）が条件
- Windows：`winget install LLVM.LLVM` と `perry setup windows`（約1.5GB、Visual Studio不要）、またはMSVC Build Tools

npmのパッケージ名は `@perryts/perry`、GitHubの組織名もPerryTS、公式サイトはperryts.comです。公式の配布物を確認するときは、npmのスコープ、GitHubの組織名、公式サイトのドメインを照合してください。

### hello.tsのコンパイルと実行結果

1行のファイルを用意し、`perry compile` に渡すと実行ファイルができます。以下はIntel Macでの実行結果です。

```
$ cat hello.ts
console.log("Hello, Perry");

$ perry compile hello.ts -o hello
Collecting modules...
Found 1 module(s): 1 native, 0 JavaScript
Generating code...
perry: in-process LLVM backend active (LLVM 22.1.8)
  note: Perry workspace source not found — linking the prebuilt full stdlib (larger binary).
Linking (runtime-only)...
Wrote executable: hello
Binary size: 14.3MB

$ ./hello
Hello, Perry
```

コンパイルと実行を1度に済ませる `perry run`、保存のたびに再コンパイルする `perry dev`、コンパイルせずに互換性だけ調べる `perry check`、署名からストア提出までをまとめる `perry publish` も同じCLIに入っています。

## Intel Macで実測したバイナリサイズと起動時間

READMEはhello worldを「約330KB」、ドキュメントのサイズ表は「約300KB」としています。ところがGitHub Releasesで配布されているmacOS x86\_64版（v0.5.1520）でコンパイルすると、hello worldは14.3MB（14,959,952バイト）でした。上のログにある `note` が理由で、Perryのソースツリーが手元に無いと、使う機能だけを組み直すサイズ最適化ビルドが働かず、ビルド済みの標準ライブラリを丸ごとリンクします。ソースツリーの場所は環境変数 `PERRY_WORKSPACE_ROOT` で指定します。

サイズは大きくても依存は少なく、`otool -L` で確認したhello worldの動的リンク先は `libSystem.B.dylib` の1本だけでした。Node.jsの追加インストールは不要ですが、配布先のMacが対応するCPUアーキテクチャ・命令セット・macOSの条件を満たす必要があります。計測は2026年10月8日、Intel Core i9-9880H（2.3GHz）を積んだmacOS 26（Darwin 25.6）のMacで、GitHub Releasesの `perry-macos-x86_64.tar.gz`（v0.5.1520）を既定オプションの `perry compile` でビルドして行いました。起動時間はPythonの `subprocess.run` で標準出力を捨てて10回連続実行した中央値で、Node.js側は同じ1行の `hello.js` を `node hello.js` で実行しています。fib(35)は各実行ファイル内で `Date.now()` の差を取り、5回実行しました（Perryは109〜131ms、Node.jsは293〜325ms）。

| 計測項目                       | Perry 0.5.1520 | Node.js v26.5.0 |
| -------------------------- | -------------- | --------------- |
| hello worldのファイルサイズ        | 14.3MB         | （Node.js本体が必要）  |
| UIカウンターアプリのサイズ             | 14.5MB         | ―               |
| hello worldの起動〜終了（10回の中央値） | 32.9ms         | 253.2ms         |
| 再帰fib(35)の計算時間（5回の中央値）     | 114ms          | 309ms           |

起動時間で約7.7倍、再帰呼び出しの計算で約2.7倍の差がつきました。fib(35)の実行中にはNode.jsのJIT最適化も働くため、この差をウォームアップの有無だけでは説明できません。一方、[READMEの公開ベンチマーク一覧](https://github.com/PerryTS/perry#performance)には負けている行も載っています。Apple M1 Max上の計測で、クラスのメソッド呼び出し（method\_calls）はPerry 35msに対しNode.js 11ms、木構造の割り当て（binary\_trees）は13msに対し6msでした。オブジェクト指向の呼び出しが多いコードでは、Node.jsより遅くなる場面があると見込んでおくべきです。

配布時にもう1つ注意があります。`perry compile --help` によると、ホスト向けビルドの既定は `--march native` で、ビルドしたマシンのCPU命令（AVX-512など）を使います。古いx86-64 CPUで動かす可能性があるなら、`--march generic` か `x86-64-v2` のように固定します。Linuxで外部ライブラリに依存しない完全静的バイナリが欲しいときは `--libc musl` を付けます。

## TypeScriptの対応範囲と言語機能の制限

### Perryの型注釈の扱いと型検査の設定

Perryは型注釈を消してからコードを生成するため、`string` と宣言した引数に数値が渡っても実行時に例外は出ません。型の推論はPerry独自のエンジンで行い、完全な型検査はしません。tscと同じ精度で型エラーを拾いたい場合は `--type-check` を付け、MicrosoftのTypeScript型検査器と連携させます（型システムのドキュメントより）。

### eval・new Functionの文字列リテラル対応と実行時の制限

`eval("1 + 1")` のように中身が文字列リテラルで書かれていれば、Perryはそれをネイティブ関数としてコンパイルし、実行すると `2` を返しました。実行時に組み立てた文字列は事前コンパイルできないため、既定ではビルドを止めずに「到達したら例外を投げる値」に置き換えます。ここで紛らわしいのが、`const` 変数に入れた文字列も実行時扱いになる点です。

```
const code = "1+1";
console.log(eval(code));
```

このファイルは `perry check` が「All checks passed」を返し、コンパイルも末尾の注意書き（notice）だけで成功します。ところが実行すると `Error: eval() cannot run in an ahead-of-time compiled binary` で止まりました。互換チェックを通ったから本番で動くとは限りません。`--strict-eval` を付ける（または `package.json` に `"perry": { "strict": true }` を書く）と、同じコードは `error[U006]` でビルドが失敗します。CIでは厳格モードを既定にしておくと、実行時の事故を避けられます。実行時に計算したパスを渡す `import(spec)` にも同じ扱いが適用されます。

### Node.js互換と同梱されるnpmパッケージ

READMEは、Node.js自身のテストスイートで53の `node:*` モジュールにわたり約97%が通ると公称しています。v0.5.1520のmacOS版アーカイブには、fastify・pg・mysql2・mongodb・ioredis・ws・bcrypt・jsonwebtoken・sharp・axiosなど40本のパッケージをネイティブ実装した静的ライブラリ（`libperry_ext_*.a`）が入っていました。

制約は「コンパイル時に見えないコードは動かない」ことです。[制限事項のドキュメント](https://perryts.github.io/perry/language/limitations.html)は、実行時にインストールされたnpmプラグインやローカルのJS／TSプラグインを読み込めないと明記しています。Perryで共有ライブラリにコンパイルしたネイティブプラグインを `loadPlugin` で読み込む仕組みはありますが、JS／TSのプラグインをそのまま持ち込む設計は移植できません。また、`node_modules` 内の素のJavaScriptファイルはQuickJSベースの `perry-jsruntime` で動かす経路があり、これは `perry.allowJsRuntime` などで明示的に許可したときだけリンクされます（[JSランタイムのオプトイン](https://perryts.github.io/perry/cli/allow-js-runtime.html)）。プラグイン前提のアプリにはJavaScriptエンジンを内蔵する方式が向いており、その代表であるBunの互換範囲は[Bun 1.4とは？Rust実装への移行とNode.js互換の実測範囲を実装目線で解説](/tech/details/16888/)でまとめています。

## ネイティブUIと対応プラットフォーム

Perryの `perry/ui` は、SwiftUIに近い宣言的なAPIを各OSの標準ウィジェットに対応づけます。WebViewやブラウザエンジンは使いません。[プラットフォーム概要のドキュメント](https://perryts.github.io/perry/platforms/overview.html)は10系統を挙げています（READMEはiPadOSを分けて11と数えています）。

| プラットフォーム | –target   | UIツールキット        | 対応状況              |
| -------- | --------- | --------------- | ----------------- |
| macOS    | （既定）      | AppKit          | 127/127           |
| iOS      | ios       | UIKit           | 127/127           |
| visionOS | visionos  | UIKit           | 2Dウィンドウのみ         |
| tvOS     | tvos      | UIKit           | フォーカス・ゲームコントローラ対応 |
| watchOS  | watchos   | SwiftUI         | 15ウィジェット          |
| Android  | android   | JNI／Android SDK | 112/112           |
| Wear OS  | wearos    | JNI／Android SDK | Androidと共通        |
| Windows  | windows   | Win32           | 112/112           |
| Linux    | linux     | GTK4            | 112/112           |
| Web      | web（wasm） | DOM／CSS         | 168ウィジェット         |

「127/127」「112/112」はUI関数の実装数です。Apple系の127に対しAndroid・Windows・Linuxは112なので、macOSで書いたUIを他のOSへ持っていくときは、使っている関数が対象OSにあるかを確認します。次は公式サンプルのカウンターアプリで、テンプレートリテラル内の `count.value` が状態に結びつき、ボタンを押すと表示が更新されます。

```
import { App, VStack, Text, Button, State } from "perry/ui"

const count = State(0)

App({
    title: "Counter",
    width: 400,
    height: 300,
    body: VStack(16, [
        Text(`Count: ${count.value}`),
        Button("Increment", () => count.set(count.value + 1)),
    ]),
})
```

Intel Macでコンパイルすると14.5MBの実行ファイルになり、AppKitやCoreGraphicsなどOS標準のフレームワークを動的にリンクしていました。

## parallelMap・spawnによるマルチスレッド処理と書き込み禁止の規則

`perry/thread` は `parallelMap`・`parallelFilter`・`spawn` の3つを提供します。`parallelMap` と `parallelFilter` は配列をCPUコア数に分けてOSスレッドで処理し、小さな配列ではスレッドを作らずその場で処理します。`spawn` は処理をバックグラウンドのスレッドで実行し、Promiseを返します。Node.jsの `worker_threads` のようにエンジンのインスタンスを別に立てる方式ではありません。通常のキャプチャ値はコピーされ、外側の変数への書き込みはコンパイル時に拒否されます。ただし `SharedArrayBuffer` 自体は共有され、各スレッドで型付き配列のビューを作って `Atomics` で同期できます。モジュール直下に置いた配列やオブジェクトはワーカーから読むこともできず、関数内のローカル変数に代入してから取り込みます（[マルチスレッドのドキュメント](https://perryts.github.io/perry/threading/overview.html)より）。

```
import { parallelMap } from "perry/thread";

let counter = 0;
const out = parallelMap([1, 2, 3, 4], (x: number) => {
  counter += x;   // 外側の変数への書き込み
  return x * 2;
});
```

このコードは `` closure passed to `parallelMap` writes to outer variable `` というエラーでリンク前に止まり、「クロージャから値を返してメインスレッドで集計せよ」と案内されます。外側の数値定数を読む今回の例では問題なく、`parallelMap([1, 2, 3, 4], (x: number) => x * factor)`（`factor = 3`）は `[ 3, 6, 9, 12 ]` を返しました。合計値やカウンターが必要な処理は、要素ごとの結果を返して `reduce` で畳む形に書き換えます。

## Electron・Tauri・React Native・Flutterとの違いと採用判断

### Perryと既存UIフレームワークの描画方式・ランタイム比較

4つの技術とPerryの差は、UIを誰が描くかと、実行時に何が動くかに集約されます。

- Electron：ChromiumとNode.jsをアプリごとに同梱し、HTML／CSSで描く。仕組みは[Electronとは？Web技術でデスクトップアプリを作る入門解説【2026年最新】](/tech/details/3322/)を参照
- Tauri：OS標準のWebViewでHTML／CSSを描き、バックエンドはRust。比較は[Tauriとは？Electronとの違い・将来性・始め方まで徹底解説【2026年版】](/tech/details/4114/)を参照
- React Native：JavaScriptエンジン上でReactを動かし、ネイティブビューを操作する
- Flutter：Dartで書き、独自のレンダリングエンジンが画面を描く
- Perry：TypeScriptを機械語に変換し、AppKitやWin32などOS標準のウィジェットを直接呼ぶ。実行時にJavaScriptエンジンもWebViewも無い

HTMLやCSSの資産をそのまま使いたいならElectronかTauri、TypeScriptのまま実行時のエンジンを無くしたいならPerryという分かれ方です。

### Perryを選ぶ場面と見送る場面

2026年10月時点のPerryは、社内向けCLIやサーバーの単一バイナリ化、小規模なデスクトップツールで試すのが適切です。起動が速く、配布先にNode.jsを入れなくてよい利点が、多少の互換性の穴より大きく効くからです。`fastify` や `pg` を使うAPIサーバーを、`node_modules` を持ち込まずに1ファイルで配れる点も運用を軽くします。

逆に、次の条件に1つでも当てはまるなら、現時点での本番採用は見送るべきです。

- 実行時に未コンパイルのJS／TSプラグインを読み込む、またはユーザー入力から `eval` や動的 `import` を組み立てる設計になっている
- クラスのメソッド呼び出しが多い主要処理を対象環境で比較し、Perryでは必要な処理時間やスループットを満たせない
- ストアで長期運用するモバイルアプリで、ビルドの再現性を数年単位で保つ必要がある（0.5系で、GitHub Releasesは累計159件。2026年10月8日時点の未解決issueはプルリクエストを除いて189件）

導入前の確認には `perry check` を使いますが、前述のとおり `eval` の問題はこれでは見つかりません。`--strict-eval` を付けたビルドと、主要な処理を実際に動かすテストまで回してから判断します。

## よくある質問

### Perryは無料で使えますか？

使えます。コンパイラ本体はMITライセンスで、GitHubのPerryTS/perryで公開されています。テレメトリは初期状態で無効で、`PERRY_NO_TELEMETRY=1` を設定すると常に送信されません。

### WindowsでもPerryを使えますか？

使えます。`winget install PerryTS.Perry` で入り、リンクにはLLVMと `perry setup windows` を使う方法か、MSVC Build Toolsを使う方法を選べます。ビルド先の指定は `--target windows` で、ARM版Windows向けの `windows-aarch64` も選べます。

### 既存のNode.jsプロジェクトはそのままコンパイルできますか？

静的に `import` しているコードの多くはコンパイルできますが、すべてではありません。実行時に読み込むプラグインや、実行時に組み立てた文字列の `eval` は動きません。まず `perry check` と `--strict-eval` 付きのビルドで問題箇所を洗い出してください。

### Bunの単一バイナリ化とPerryは何が違いますか？

Bunが作る単一バイナリはJavaScriptエンジンを内蔵し、実行時にJITで動きます。Perryは事前に機械語へ変換し、エンジンを持ちません。今回のhello worldでは起動時間が短くなりました。ただし、未コンパイルのJS／TSを実行時に読み込む方式には制約があります。Perryで事前コンパイルしたネイティブプラグインの読み込みは可能です。

### 「perryts」とPerryは同じものですか？

同じです。GitHubの組織名とnpmのスコープが `perryts`、公式サイトがperryts.com、ドキュメントはperryts.github.io/perryにあります。コンパイラのリポジトリはPerryTS/perryです。

## 関連記事

- [scriptcとは？TypeScriptをC経由でネイティブ化する仕組みと採用条件](/tech/details/16379/)
- [SWCとは？Rust製コンパイラの設定と採用判断を実装目線で解説](/tech/details/16019/)
- [Bun 1.4とは？Rust実装への移行とNode.js互換の実測範囲を実装目線で解説](/tech/details/16888/)
- [Tauriとは？Electronとの違い・将来性・始め方まで徹底解説【2026年版】](/tech/details/4114/)
- [Electronとは？Web技術でデスクトップアプリを作る入門解説【2026年最新】](/tech/details/3322/)

---

出典: [Perryとは？TypeScriptをネイティブバイナリへ直接コンパイルする仕組みと実測【v0.5.1520】](<https://www.issoh.co.jp/tech/details/12041/>)（株式会社一創）
