官方仓库:github.com/PerryTS/per… · 官方网站:www.perryts.com · 当前版本:v0.5.306
一、先说痛点:你是不是也在忍受这些?
你用 TypeScript 写了一个 CLI 工具或桌面应用,然后:
- 用户需要先装 Node.js 才能运行,体验极差
- 打包成 Electron 应用,随便一个 Hello World 就 200 MB 起步
- 冷启动要等好几秒,内存动辄吃掉 300 MB
- 想发布到 App Store?想都别想
Perry 的出现就是为了彻底解决这些问题。
二、Perry 是什么?一句话说清楚
Perry 是一个用 Rust 写的原生 TypeScript 编译器。
它把你的 .ts 文件直接编译成平台原生可执行文件,底层使用 SWC 解析 TypeScript、LLVM 生成机器码。
你的 TypeScript 代码
↓
perry compile
↓
原生二进制文件(macOS / Windows / Linux / iOS / Android / WASM…)
没有 Node.js,没有 V8,没有 Electron,没有 WebView,就是一个单文件二进制,拿来就跑。
三、整体架构图(一图胜千言)
┌─────────────────────────────────────────────────────────────┐
│ Perry 编译流水线 │
│ │
│ TypeScript (.ts) │
│ │ │
│ ▼ │
│ ┌─────────────┐ SWC 解析器(Rust 实现,速度极快) │
│ │ SWC Parser │ ← 解析 TypeScript/ES 语法树 │
│ └──────┬──────┘ │
│ │ AST (抽象语法树) │
│ ▼ │
│ ┌─────────────┐ HIR 高层中间表示 │
│ │ HIR Lower │ ← 类型擦除、泛型单态化 │
│ └──────┬──────┘ │
│ │ HIR (High-level IR) │
│ ▼ │
│ ┌─────────────┐ 优化变换阶段 │
│ │ Transform │ ← 闭包转换、async/await 展开、内联 │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ LLVM 代码生成 │
│ │ LLVM IR │ ← NaN-Boxing、逃逸分析、标量替换 │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ 系统链接器 │
│ │ Linker │ ← Xcode CLT / GCC / MSVC │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ 原生可执行文件 (~330KB ~ 5MB) │
└─────────────────────────────────────────────────────────────┘
四、跨平台目标矩阵
Perry 的最大亮点是一套代码,10 个平台目标:
┌──────────────────────────────────────────────────────────────┐
│ Perry 支持的目标平台 │
├──────────────┬──────────────────┬────────────────────────────┤
│ 平台 │ 底层 UI 框架 │ 编译命令 │
├──────────────┼──────────────────┼────────────────────────────┤
│ macOS │ AppKit │ perry compile (默认) │
│ iOS / iPadOS │ UIKit │ --target ios │
│ visionOS │ UIKit │ --target visionos │
│ tvOS │ UIKit │ --target tvos │
│ watchOS │ WatchKit │ --target watchos │
│ Android │ Android Views │ --target android │
│ Windows │ Win32 │ perry compile (默认) │
│ Linux │ GTK4 │ perry compile (默认) │
│ Web │ DOM (JS 输出) │ --target web │
│ WebAssembly │ DOM (WASM) │ --target wasm │
└──────────────┴──────────────────┴────────────────────────────┘
五、安装(5 分钟上手)
方式一:npm / npx(推荐,零门槛)
# 项目本地安装(推荐,锁定版本)
npm install @perryts/perry
# 全局安装
npm install -g @perryts/perry
# 零安装,一次性试用
npx -y @perryts/perry compile src/main.ts -o myapp
方式二:Homebrew(macOS)
brew install perryts/perry/perry
方式三:winget(Windows)
winget install PerryTS.Perry
方式四:APT(Ubuntu / Debian)
curl -fsSL https://perryts.github.io/perry-apt/perry.gpg.pub | sudo gpg --dearmor -o /usr/share/keyrings/perry.gpg
echo "deb [signed-by=/usr/share/keyrings/perry.gpg] https://perryts.github.io/perry-apt stable main" | sudo tee /etc/apt/sources.list.d/perry.list
sudo apt update && sudo apt install perry
安装完后验证环境:
perry doctor
六、从零开始:三个由浅入深的示例
🟢 示例一(入门级):Hello World
创建 hello.ts:
const greeting: string = "Hello, Perry!";
console.log(greeting);
编译并运行:
perry compile hello.ts -o hello
./hello
# Hello, Perry!
产物是一个约 330KB 的独立二进制,不需要任何运行时依赖。
🟡 示例二(进阶级):文件读写 + HTTP 服务器
Perry 内置了与 Node.js 兼容的标准库,直接用熟悉的 API。
// server.ts
import fastify from 'fastify';
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
const app = fastify({ logger: true });
// 读取配置文件
const configPath = join(process.cwd(), 'config.json');
const config = existsSync(configPath)
? JSON.parse(readFileSync(configPath, 'utf-8'))
: { port: 3000 };
// 路由定义
app.get('/health', async () => {
return { status: 'ok', uptime: process.uptime() };
});
app.get('/api/users', async () => {
return [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
];
});
app.post('/api/users', async (req, reply) => {
const body = req.body as { name: string };
return reply.code(201).send({ id: Date.now(), name: body.name });
});
// 启动服务
app.listen({ port: config.port }, () => {
console.log(`Server running on http://localhost:${config.port}`);
});
编译成独立服务器:
perry compile server.ts -o server
./server
# 启动!无需 node_modules,无需 Node.js 环境
Perry 对 fastify、mysql2、ioredis、bcrypt 等常用包做了原生 Rust 重实现,导入语法完全相同,性能是 Node.js 版的数倍。
🔴 示例三(高级):多文件项目 + 原生 GUI + 多线程
这个示例展示 Perry 最强大的能力:原生桌面 GUI + 真正的多线程。
项目结构:
my-app/
├── src/
│ ├── main.ts ← 程序入口
│ ├── ui.ts ← 原生 GUI 界面
│ └── worker.ts ← 多线程计算
└── package.json
src/worker.ts — 多线程计算:
import { parallelMap, parallelFilter, spawn } from 'perry/thread';
// 并行 Fibonacci 计算(跑满所有 CPU 核心)
export async function computeFibBatch(inputs: number[]): Promise<number[]> {
return parallelMap(inputs, (n) => {
const fib = (x: number): number => x <= 1 ? x : fib(x - 1) + fib(x - 2);
return fib(n);
});
}
// 后台线程执行耗时任务,不阻塞 UI
export async function heavyTask(): Promise<string> {
return spawn(() => {
// 这段代码在独立 OS 线程中运行
let sum = 0;
for (let i = 0; i < 100_000_000; i++) sum += i;
return `Result: ${sum}`;
});
}
src/ui.ts — 原生 GUI 界面:
import {
App, VStack, HStack, Text, Button, Spacer,
stackSetDistribution, stackSetAlignment,
} from 'perry/ui';
import { computeFibBatch, heavyTask } from './worker';
// 侧边栏
const sidebar = VStack(8, [
Text("🔢 Perry Demo"),
Text("Fibonacci"),
Text("Heavy Task"),
Spacer(),
]);
sidebar.setEdgeInsets(12, 12, 12, 12);
sidebar.setBackgroundColor("#1e1e2e");
// 主内容区
const resultText = Text("点击按钮开始计算...");
const fibBtn = Button("计算 fib(1..10) 并行", async () => {
const results = await computeFibBatch([1,2,3,4,5,6,7,8,9,10]);
resultText.setText(`结果: ${results.join(', ')}`);
});
const heavyBtn = Button("后台耗时任务", async () => {
resultText.setText("计算中...");
const result = await heavyTask();
resultText.setText(result);
});
const actions = HStack(8, [fibBtn, heavyBtn]);
stackSetDistribution(actions, 1); // 两个按钮等宽
const content = VStack(16, [
Text("Perry 原生 GUI 示例"),
resultText,
Spacer(),
actions,
]);
content.setEdgeInsets(20, 20, 20, 20);
stackSetAlignment(content, 5); // Leading 对齐
export { sidebar, content };
src/main.ts — 程序入口:
import { App, SplitView, splitViewAddChild } from 'perry/ui';
import { sidebar, content } from './ui';
const split = SplitView();
splitViewAddChild(split, sidebar);
splitViewAddChild(split, content);
App({ title: 'Perry Demo', width: 900, height: 600, body: split });
编译并运行:
perry compile src/main.ts -o demo
./demo # macOS 用 AppKit 渲染
# 或
perry compile src/main.ts --target android -o DemoApp # Android 原生
UI 架构示意图:
┌────────────────────────────────────────────────┐
│ Perry App (原生窗口,AppKit / Win32 / GTK4) │
│ │
│ ┌──────────┐ ┌──────────────────────────────┐ │
│ │ Sidebar │ │ Content │ │
│ │ VStack │ │ VStack │ │
│ │ │ │ │ │
│ │ Text │ │ Text "Perry Demo" │ │
│ │ Text │ │ Text resultText ← 动态更新 │ │
│ │ Text │ │ Spacer │ │
│ │ Spacer │ │ │ │
│ │ │ │ HStack (FillEqually) │ │
│ │ │ │ ┌──────────┬──────────────┐ │ │
│ │ │ │ │ fibBtn │ heavyBtn │ │ │
│ │ │ │ └──────────┴──────────────┘ │ │
│ └──────────┘ └──────────────────────────────┘ │
└────────────────────────────────────────────────┘
↑ 真正的原生组件,不是 WebView!
七、性能:真的有多快?
这是 Perry 官方基准测试(Apple Silicon M1,和 Node.js v25 对比):
┌────────────────┬────────┬──────────┬────────┬────────────────────┐
│ 测试项 │ Perry │ Node.js │ Bun │ Perry 优势 │
├────────────────┼────────┼──────────┼────────┼────────────────────┤
│ 闭包创建(1000万)│ 10ms │ 309ms │ 51ms │ 🚀 31x faster │
│ 阶乘(模运算) │ 31ms │ 596ms │ 98ms │ 🚀 19x faster │
│ 类方法调用 │ 1ms │ 11ms │ 9ms │ 🚀 11x faster │
│ 数值循环(1亿) │ 15ms │ 61ms │ 50ms │ 🚀 4x faster │
│ 调和级数(5000万)│ 14ms │ 52ms │ 52ms │ 🚀 3.7x faster │
│ 斐波那契(40) │ 320ms │ 1033ms │ 521ms │ 🚀 3.2x faster │
│ JSON 往返 │ 314ms │ 377ms │ 250ms │ ✅ 同量级 │
└────────────────┴────────┴──────────┴────────┴────────────────────┘
二进制大小对比:
Perry Hello World ████ ~330 KB
Perry + 完整 stdlib ████████████████████ ~5 MB
Node.js 运行时 ████████████████████████████████████████ ~80 MB
Bun 运行时 ████████████████████████████████████████ ~90 MB
八、Perry 凭什么这么快?编译器优化揭秘
Perry 的性能来自多层优化,用流程图来理解:
┌────────────────────────────────────────────────────────┐
│ Perry 核心优化技术 │
│ │
│ ① NaN-Boxing │
│ 所有值用 64-bit 表示(f64/u64 复用), │
│ 数字无需装箱,直接寄存器操作 │
│ │
│ ② 逃逸分析 + 标量替换 (Scalar Replacement) │
│ let p = new Point(x, y); sum += p.x + p.y; │
│ → p 不逃逸 → 字段直接变成寄存器变量 │
│ → 零堆分配! │
│ │
│ ③ 内联 Bump 分配器 │
│ 逃逸对象用 13 指令内联 arena bump │
│ → 不调用 malloc,热路径无函数调用开销 │
│ │
│ ④ Fast-Math 标志 (reassoc + contract) │
│ → 打破串行累加器依赖链 │
│ → LLVM 自动向量化为 <2 x double> 并行累加 │
│ │
│ ⑤ i64 特化 │
│ 纯数值递归函数 → 原生 i64 寄存器 │
│ → 整数模运算: fptosi→srem→sitofp(比 fmod 快 64x) │
│ │
│ ⑥ 并行编译 (rayon) │
│ 模块代码生成、IR 优化、符号扫描 → 多核并行 │
└────────────────────────────────────────────────────────┘
九、关键特性速览
原生 npm 包支持(无需 Node.js)
Perry 对以下包做了 Rust 原生重实现,直接 import 就用:
| 分类 | 支持的包 |
|---|---|
| HTTP | fastify, axios, node-fetch, ws |
| 数据库 | mysql2, pg, ioredis, mongodb, better-sqlite3 |
| 安全 | bcrypt, argon2, jsonwebtoken |
| 工具 | dotenv, uuid, nodemailer, zlib, node-cron |
| 数据处理 | cheerio, sharp, lodash, date-fns |
如果需要使用纯 JS 的 npm 包(不在原生支持列表中),可以启用可选的 V8 嵌入:
perry compile src/main.ts --enable-js-runtime -o myapp
# 体积增加约 15MB,换来完整 npm 生态兼容
编译时国际化(i18n)
import { t, Currency, ShortDate } from 'perry/i18n';
console.log(t('hello')); // "Hallo"(德语环境)
console.log(t('items', { count: 3 })); // "3 Artikel"(CLDR 复数规则)
console.log(Currency(9.99, 'EUR')); // "9,99 €"
console.log(ShortDate(Date.now())); // "24.03.2026"
所有翻译字符串在编译时烘焙进二进制,运行时零查找开销。在 perry.toml 配置:
[i18n]
default_locale = "en"
locales = ["en", "de", "fr", "ja"]
原生 React(perry-react)
用你熟悉的 React 写原生桌面/移动 App:
import { useState } from 'react';
import { createRoot } from 'react-dom/client';
function Counter() {
const [n, setN] = useState(0);
return (
<div>
<h1>Count: {n}</h1>
<button onClick={() => setN(n + 1)}>+</button>
</div>
);
}
// 渲染到原生窗口,不是 DOM!
createRoot(null, { title: 'Counter', width: 300, height: 200 }).render(<Counter />);
插件系统(编译时链接)
// my-plugin.ts
import { PluginRegistry } from 'perry/plugin';
export function activate(api: any) {
api.registerTool('my-tool', (args: any) => {
return `Processed: ${JSON.stringify(args)}`;
});
}
# 编译成原生动态库
perry compile my-plugin.ts --output-type dylib -o my-plugin.dylib
插件在编译期直接链接,没有运行时 IPC 开销。
十、工程项目结构(生产级)
Perry 官方 8 个示例项目,覆盖常见生产场景:
example-code/
├── express-postgres/ ← Express + PostgreSQL,多文件路由、中间件
├── fastify-redis-mysql/ ← Fastify + Redis + MySQL,限速、缓存层
├── hono-mongodb/ ← 轻量 HTTP + MongoDB 文档数据库
├── nestjs-typeorm/ ← NestJS + TypeORM,装饰器架构、依赖注入
├── nextjs-prisma/ ← Prisma ORM,数据库迁移
├── koa-redis/ ← Koa 中间件组合,Session 存储
├── http-server/ ← 原生 HTTP,低层路由
└── blockchain-demo/ ← 纯 TypeScript 区块链实现
任意一个都可以直接编译运行:
cd example-code/fastify-redis-mysql
npm install
perry compile src/index.ts -o server
./server
十一、发布流程:从代码到 App Store
Perry 提供完整的云端发布流程:
┌────────────┐ perry compile ┌──────────────┐
│ TypeScript │ ─────────────────→ │ 本地二进制 │
│ 源代码 │ │ (开发测试用) │
└────────────┘ └──────────────┘
│
│ perry publish ios/android/macos
↓
┌──────────────┐
│ perry-hub │ ← 云端交叉编译 + 代码签名服务
│ (云端构建) │
└──────┬───────┘
│
├──→ App Store (iOS / macOS)
├──→ Play Store (Android)
└──→ 直接下载包 (Linux / Windows)
# 一条命令完成交叉编译、签名和提交
perry publish ios
perry publish android
perry publish macos
十二、UI 测试框架(Geisterhand)
Perry 内置了名为 Geisterhand 的 UI 自动化测试框架:
# 编译时启用测试服务器
perry compile src/main.ts --enable-geisterhand -o myapp
./myapp
# 测试服务器在 http://localhost:7676 暴露 HTTP API
# 支持截图、点击、输入等操作,覆盖全平台
十三、对比其他跨平台方案
┌─────────────┬──────────────┬────────────┬──────────────┬──────────────┐
│ 框架 │ 语言 │ 原生控件 │ 运行时开销 │ 二进制大小 │
├─────────────┼──────────────┼────────────┼──────────────┼──────────────┤
│ Perry ★ │ TypeScript │ ✅ 真原生 │ ❌ 无 │ 2-5 MB │
│ React Native│ JS/TS │ ✅ 原生 │ ⚠️ Hermes/V8 │ ~60 MB │
│ Flutter │ Dart │ ❌ 自绘 │ ⚠️ Dart VM │ ~20 MB │
│ Electron │ JS/TS │ ❌ WebView │ ⚠️ V8+Chrome │ ~150 MB │
│ Tauri │ JS/TS+Rust │ ❌ WebView │ ⚠️ 系统WebV │ ~10 MB │
│ NativeScript│ JS/TS │ ✅ 原生 │ ⚠️ V8/JSCore │ ~30 MB │
└─────────────┴──────────────┴────────────┴──────────────┴──────────────┘
Perry 是目前唯一做到"TypeScript + 零运行时 + 真原生控件"的框架。
十四、编译器内部结构(给想深挖的开发者)
perry/crates/
├── perry/ ← CLI 入口(compile、run、check、init…)
├── perry-parser/ ← SWC TypeScript 解析器封装
├── perry-types/ ← 类型系统
├── perry-hir/ ← HIR 数据结构 + AST→HIR 降级
├── perry-transform/ ← IR 优化 Pass(闭包转换、async 展开、内联)
├── perry-codegen/ ← LLVM 原生代码生成(核心!)
├── perry-codegen-js/ ← JavaScript 目标代码生成(--target web)
├── perry-codegen-wasm/ ← WebAssembly 目标代码生成
├── perry-runtime/ ← 运行时(NaN-Boxing、GC、Arena、字符串)
├── perry-stdlib/ ← Node.js API 支持(fastify、mysql2、redis…)
├── perry-ui-*/ ← 各平台原生 UI(macOS、iOS、Android、GTK4…)
├── perry-ui-geisterhand/ ← UI 测试框架
└── perry-diagnostics/ ← 错误报告
如果你想贡献新特性,流程是:
1. crates/perry-hir/src/ir.rs → 添加 HIR 节点类型
2. crates/perry-hir/src/lower.rs → 处理 AST→HIR 降级逻辑
3. crates/perry-codegen/src/codegen.rs → 生成对应 LLVM IR
4. crates/perry-runtime/ → 如需添加运行时函数
5. test-files/test_feature.ts → 添加测试用例
十五、常用命令速查卡
# 基础编译
perry compile src/main.ts -o myapp
# 编译并直接运行
perry run .
# 初始化新项目
perry init my-project
# TypeScript 兼容性检查(不编译)
perry check src/
# 环境诊断
perry doctor
# 提取 i18n 字符串
perry i18n extract
# 跨平台目标
perry compile src/main.ts --target ios -o MyApp
perry compile src/main.ts --target android -o MyApp
perry compile src/main.ts --target web -o app.html
perry compile src/main.ts --target wasm -o app.wasm
# 编译为动态库(插件)
perry compile plugin.ts --output-type dylib -o plugin.dylib
# 启用 V8 运行时(兼容更多 npm 包)
perry compile src/main.ts --enable-js-runtime -o myapp
# 调试用:打印 HIR
perry compile src/main.ts --print-hir
十六、目前的局限性
Perry 目前不支持的 TypeScript 特性:
@Decorator(装饰器)暂不支持- 运行时类型检查(类型在编译时全部擦除,运行时用
typeof/instanceof) - 单线程默认模型(主线程 + Tokio 异步 I/O;多线程需显式用
perry/thread)
十七、总结
Perry 是一个非常有野心的项目——它的目标是让 TypeScript 真正成为一门"全平台原生开发语言",而不只是浏览器/Node.js 的专利。
适合 Perry 的场景:
- CLI 工具(体积小,分发方便,无依赖)
- 需要高性能的后端服务(避开 V8 JIT 不稳定性)
- 跨平台桌面/移动 App(一套 TS 代码,10 个平台)
- 对启动速度和内存极度敏感的场景
- 想发布到 App Store / Play Store 的 TypeScript 开发者
不太适合的场景:
- 大量依赖 Node.js 生态原生扩展(
.node文件)的项目 - 重度使用 Decorator 元编程的项目(暂不支持)
- 已有成熟 Electron 应用且无性能问题的维护阶段项目
从 2.2k star 和真实应用案例(Mango、Hone、dB Meter 等已上架)来看,Perry 已经在朝着"TypeScript 的 Rust"方向稳步前进,值得每一位 TypeScript 开发者关注和尝鲜。
📌 快速体验:
npx -y @perryts/perry compile hello.ts -o hello && ./hello🌐 官网:www.perryts.com | 📦 GitHub:github.com/PerryTS/per…