TypeScriptCompilation

TypeScript 终于能编译成原生程序了?启动快 12 倍,运行却慢 7.5 倍

Daniel Curtis(译者:田橙)··原文链接
收录于 2026/10/12 09:51:40

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 基准测试:

指标scriptcBunNode
启动时间中位数1.78 ms21.29 ms61.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 翻译)

评分:
暂无(0 人评分)