TypeScript 终于能编译成原生程序了?启动快 12 倍,运行却慢 7.5 倍
Vercel Labs 发布了 scriptc——一款 Apache 2.0 许可的实验性编译器,能将普通 TypeScript 编译为不包含 Node、V8 或任何 JavaScript 引擎的小型原生可执行文件。代码仓库创建于 2026 年 7 月 22 日,目前约 4900 Star。
工作原理:类型化中间表示 + 三层分级
scriptc 使用真正的 TypeScript 编译器进行解析和类型检查,将程序转换为类型化中间表示(typed IR),随后可生成可读 C 代码、LLVM IR、汇编、目标文件、原生可执行文件,或通过 WASI Preview 1 生成 WebAssembly。
类比:这和 React 编译器(React Compiler / Forget)的思路相近——都是把原本依赖运行时解释的高级结构,静态编译为更底层的产物。区别在于 React Compiler 产出的是优化后的 JS/IR,而 scriptc 直接跨到原生二进制。
每一种语法结构会被划入三个层级之一:
- 默认静态编译:类型安全的部分直接编译为原生代码;
- 动态执行孤岛:对 npm 软件包和
any类型代码,传入--dynamic参数时由内嵌的约 620KB quickjs-ng 引擎动态执行; - 编译时拒绝:返回 SC 错误码和改写建议。
性能数据:启动快、内存小,但运行慢
scriptc 0.0.16 vs Bun 1.3.12 / Node 24.18.0 基准测试:
| 指标 | scriptc | Bun | Node |
|---|---|---|---|
| 启动时间中位数 | 1.78 ms | 21.29 ms | 61.78 ms |
| 空闲服务器内存 | 1.9 MiB | — | — |
Hacker News 上开发者的实测更完整:启动快 12 倍(1.5 ms vs 18.6 ms)、内存低 72 倍(2.5 MiB vs 181 MiB)、产物仅 370KB 单一可执行文件无运行时依赖——但运行速度慢约 7.5 倍。
一个不使用框架的 node:http 服务器在空闲时仅占 1.9 MiB。但 Hono 必须启用 --dynamic,导致 62% 代码进入 QuickJS,吞吐量降至每秒 1.84 万请求,而 Bun 可达每秒 7.05 万。
工程判断:这和 SSR vs CSR 的取舍如出一辙。启动快、内存低适合 CLI 工具、Serverless 冷启动场景;但一旦进入计算密集或依赖大量 npm 生态的 Web 服务场景,运行时性能劣势会被放大。
专家批评:浮点化 + 依赖 QuickJS 是硬伤
Filip Pizlo(知名 JS 引擎专家)指出,scriptc 将所有数字表示为浮点数并暂缓整数类型推断,相当于"跳过了让 JavaScript 跑得快这一问题的一半"。对以性能为目标的项目,依赖 QuickJS 不合适——any 足够常见,实际程序代码会不断落入动态执行孤岛,性能不可控。
对前端的类比:这就像整个应用都用了
any类型后再做 AOT 编译——类型信息丢失后,编译器只能退化到解释执行,优化空间被锁死。
生态兼容性:数百个错误,"基本毫无用处"
一名开发者用本地所有项目做兼容性覆盖检查,每个项目都产生数百个错误:
尽管它受到了很多批评,我还是测试了一遍。每个项目的覆盖检查都会产生数百个错误,所以它基本毫无用处。我可以从头写一个不依赖任何第三方库的项目再编译;但既然如此,我为什么不用 Rust、Go、Zig、C、Nim……这些本就为编译而设计的语言?
长期维护疑虑
评论者提到 Vercel 的 zerolang 项目发布数周后便无新提交。Remo Jansen 尝试用 scriptc 编译 TypeScript 6 编译器本身,因编译器内部错误失败;他测得 scriptc 冷启动 3.6 ms(Node 48.9 ms),但计算任务耗时 2.33 秒,慢得多。
Simon Willison 补充:编码智能体一周内提交 91.8 万行代码,无需写 C/Rust 就能构建小巧二进制"似乎是一项很有价值的能力"。
安装与限制
- 需要 Node.js 24+,
npm install -g scriptc安装; - 支持 macOS / Linux / Windows / WASI Preview 1;
- 通过差分测试保证行为一致:逐字节比较与 Node 的 stdout、stderr、退出码;
- 限制说明页记录有意为之的差异:字符串 UTF-8 存储、引用计数而非 GC、
Object.keys按声明顺序、process.argv[0]值为"scriptc"; - 实验性
--npm-static参数可将指定包从动态孤岛移出做静态编译。
项目仍标记为实验性,文档见 scriptc.dev。
给 Rainsho 的结论:scriptc 在"把 TS 编译成原生二进制"这一方向上做出了有意义的探索,冷启动和内存指标对 CLI/Serverless 场景有吸引力。但浮点化数值表示、对 QuickJS 的依赖、以及对真实 npm 生态的极差兼容性,使其当前不具备替代 Node/Bun 用于生产的能力。值得持续关注其类型推断和静态编译管线的演进——如果未来能像 swc/turbopack 把 TS/JSX 编译管线做扎实那样,把整数推断和第三方库静态化做好,工程价值会显著提升。
原文链接:https://www.infoq.com/news/2026/09/vercel-scriptc-node/(本文为 InfoQ 翻译)