命令行工具
PerryTS/perry avatar
PerryTS/perry

Perry:把 TypeScript 直接编译成原生二进制,但先别急着扔掉 Node

项目速览:用 Rust 编写的本机 TypeScript 编译器。使用 SWC 和 LLVM 将 TypeScript 直接编译为可执行文件。

4,834 个 Star161 个 ForkRustMIT

秒懂

它是什么?
Perry 是一个用 Rust 写的 TypeScript 编译器,基于 SWC 和 LLVM,能把 TS 代码编译成无需运行时、可直接运行的原生可执行文件。本文梳理它的机制、安装方式、性能数据背后的真相,以及它目前不适合哪些场景。
适合谁用?
Perry 适合那些已经用 TypeScript 编写、但受制于 Node 运行时体积和冷启动的 CLI 工具、桌面应用、移动端组件,以及需要多核并行但不想引入 worker_threads 的开发者。它不适合重度依赖未列出的 npm 包、需要完整 Node API 兼容、或者性能敏感且依赖 JIT 优化的场景,比如矩阵运算或素数筛选。
能商用吗?
可以。MIT 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
还在维护吗?
在维护。仓库在最近一天内有新的提交。
用什么语言写的?
主要是 Rust(依据 GitHub 的语言统计)。

以上回答依据项目的 GitHub 数据(最近同步于 2026年9月15日)和我们的分析,不构成法律意见。

开源项目深度解析

它解决的是部署问题,不是语言问题

Perry 的目标不是创造一种新语言,而是让现有的 TypeScript 代码变成不需要任何运行时的原生可执行文件。传统的 TypeScript 部署方式要么在每台服务器上装 Node,要么把整个 JS 引擎打包进应用,Electron 应用动辄上百 MB。Perry 的做法是:用 SWC 解析 TypeScript,用 LLVM 生成机器码,最终得到一个独立的二进制。README 里给出的 hello world 大小约 330 KB,一个用 Perry 构建的 MongoDB GUI 应用约 7 MB。这个数字对比 Electron 动辄几十 MB 的体积,确实值得注意。但要注意,这个大小是静态链接了所需运行时之后的结果,不是所有程序都能保持这个量级。

编译管线:SWC 解析,LLVM 生成,GC 和线程都交给编译器

Perry 的架构分成两个主要阶段。SWC 负责把 TypeScript 转成中间表示,LLVM 负责优化并生成机器码。文档提到它带有逃逸分析、标量替换和分代 GC,这些是编译期优化手段,直接作用于生成的原生代码。另一个关键设计是并行原语:parallelMap、parallelFilter 和 spawn 使用真实 OS 线程,编译器会在编译期检查共享可变状态,拒绝存在数据竞争的代码。这意味着并发安全不是靠运行时检查,而是靠编译失败来保证。这种设计比 Node 的 worker_threads 更严格,但也更受限,因为不是所有并发模式都能通过它的静态检查。

安装和第一个二进制:npm 全局装,perry 命令跑

安装方式有三种,覆盖主流平台:npm install -g @perryts/perry,或者 brew install perryts/perry/perry,Windows 上可以用 winget install PerryTS.Perry。创建项目用 perry init my-app,然后 perry run . 就能跑。编译成二进制是 perry compile src/main.ts -o myapp,生成的文件直接 ./myapp 执行。README 强调 npm 包和 ES 模块可以正常使用,给出的例子是 import fastify from 'fastify',然后启动一个 HTTP 服务。这个流程对 TypeScript 开发者来说很熟悉,几乎没有学习成本。但要注意,perry run 和 perry compile 是两个不同的命令,前者可能是开发模式,后者才是产出最终二进制。

性能数据:赢了卷积,输了矩阵乘法

README 给出了多组基准测试,来源是仓库里的公开脚本和结果文件。在 4K 图像卷积、递归斐波那契、JSON 管线、对象分配和数组写入上,Perry 都比 Node 和 Bun 快,部分指标甚至接近或超过 Rust。但在完整公开套件里,它也承认输给了 V8:prime_sieve 和 matrix_multiply 两个负载,Node 和 Bun 明显更快。README 特意强调他们公布了所有数据,包括输掉的场景,没有只挑赢的。这个态度值得肯定,但读者要理解一个关键点:这些基准是编译期静态优化擅长的模式,而 V8 的 JIT 在动态类型和循环内联上有优势。如果你的代码是矩阵运算或素数筛选这类数值密集任务,Perry 可能反而更慢。

Node 兼容性:97% 的测试通过率,但 3% 可能击中你

Perry 声称对 Node 自身测试套件有约 97% 的通过率,覆盖 53 个 node:* 模块,包括 fs、http、net、crypto、stream、child_process、worker_threads 和 fetch。还列出了约 50 个流行的 npm 包,如 Fastify、Express、mysql2、pg、ioredis、ws、bcrypt、jsonwebtoken。这个列表确实覆盖了常见场景,但 97% 的通过率意味着有 3% 的测试失败,而且失败的具体模块未知。对于生产项目,这不是一个可以忽略的差异。如果你的代码依赖某个未被列出的包,或者用了 Node API 的边角行为,Perry 可能无法编译或运行出错。文档没有提供详细的兼容性矩阵,这一点需要在实际项目中验证。

多平台目标:从桌面到移动端,但 UI 是另一个世界

Perry 的亮点之一是能从同一套代码编译到 11 个目标,包括 macOS、iOS、Android、Windows、Linux,甚至 watchOS 和 TV。它提供类似 SwiftUI 的 API,但编译成真实的平台控件,而不是 WebView。这意味着你可以用 TypeScript 写一个原生 UI 应用,不需要 Electron。但这里有一个隐含的代价:UI 层不是标准的 DOM 或 React,而是 Perry 自己的抽象。如果你已经有一套 React 或 Vue 的代码,Perry 并不能直接编译它,你需要重写 UI 层。此外,iOS 和 Android 的编译可能需要额外的工具链和签名配置,README 没有详细说明这些步骤。

维护与升级:版本号频繁,但生态还在早期

Perry 的版本号更新非常频繁,最近三天内就有三个 release:v0.5.1220、v0.5.1219 和 v0.5.1182。这显示项目处于快速迭代期,但也意味着 API 可能不稳定。编译器的行为、CLI 参数、运行时库都可能随版本变化。对于生产项目,你需要锁定版本,并关注每个 release 的变更日志。许可证是 MIT,这对商业使用没有额外限制,但要注意,Perry 内部依赖 SWC 和 LLVM,它们各自的许可证也需要遵守,不过这些通常是宽松的。文档没有提供升级指南或迁移工具,所以升级成本需要自行评估。

替代方案:Bun 和 Deno 走的是另一条路

如果你需要的是更快的 TypeScript 执行,而不是完全去掉运行时,Bun 是更直接的替代品。Bun 将 JavaScript 引擎打包进单个二进制,但执行方式仍是 JIT,冷启动比 Node 快,但比 Perry 的 AOT 机器码慢。Deno 也有类似定位,内置 TypeScript 支持,但同样需要运行时。Perry 的核心差异是 AOT 编译和静态链接,这带来了更小的体积和更快的启动,但也失去了 JIT 的动态优化能力。另一个替代方案是直接写 Rust 或 Go,如果你追求极致性能,但那就放弃 TypeScript 的生态。Perry 适合那些不想离开 TypeScript,但需要原生性能的开发者。

编辑结论

Perry 适合那些已经用 TypeScript 编写、但受制于 Node 运行时体积和冷启动的 CLI 工具、桌面应用、移动端组件,以及需要多核并行但不想引入 worker_threads 的开发者。它不适合重度依赖未列出的 npm 包、需要完整 Node API 兼容、或者性能敏感且依赖 JIT 优化的场景,比如矩阵运算或素数筛选。在采纳前,你需要先跑一遍它自带的公开基准脚本 ./benchmarks/run_public_baseline.sh,确认你的典型负载不在它输给 V8 的那一行里;再拿你的实际项目试编译,看 97% 的 Node 测试通过率之外的那 3% 是否恰好命中你的代码。Perry 的承诺很大,但它的价值边界也很清晰:它是编译期优化和静态链接的产物,不是 Node 的替代品。

官方来源

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
社区笔记

社区笔记