2026-09-26
每日一文 · 长文精读
Vercel Labs Ships scriptc, a TypeScript-to-Native Compiler That Leaves the JavaScript Engine Behind
Vercel Labs 发布 scriptc:一个抛弃 JavaScript 引擎的 TypeScript 到原生编译器
作者:Daniel Curtis · InfoQ 原文
摘要:Vercel Labs 发布了实验性编译器 scriptc,能将 TypeScript 编译为无需 Node、V8 等 JavaScript 引擎的原生可执行文件。它使用 TypeScript 编译器进行解析和类型检查,生成 C、LLVM IR 等中间表示,并支持静态编译、动态运行(嵌入 QuickJS)或编译时报错。基准测试显示启动速度极快(1.78ms),内存占用低(1.9MiB),但动态运行部分性能下降。社区反馈存在兼容性问题和长期维护担忧,目前仍处于实验阶段。
Vercel Labs has released scriptc, an experimental Apache 2.0 licensed compiler that turns ordinary TypeScript into small native executables with no Node, V8 and no JavaScript engine in the binary.
Vercel Labs 发布了 scriptc,一个实验性的、采用 Apache 2.0 许可证的编译器,它能把普通的 TypeScript 转换成小巧的原生可执行文件,二进制文件中不包含 Node、V8 或任何 JavaScript 引擎。
The repository was created on 22 July 2026 and has since gathered around 4.9k stars.
该仓库创建于 2026 年 7 月 22 日,至今已收获约 4900 颗星。
scriptc uses the real TypeScript compiler for parsing and type checking, lowers programs to a typed IR, then emits readable C, LLVM IR, assembly, objects, native executables or WebAssembly via WASI Preview 1.
scriptc 使用真正的 TypeScript 编译器进行解析和类型检查,将程序降级为带类型的中间表示(IR),然后输出可读的 C 代码、LLVM IR、汇编、目标文件、原生可执行文件或通过 WASI Preview 1 输出 WebAssembly。
Every construct lands in one of three tiers: compiled statically by default, run dynamically inside an embedded quickjs-ng engine of roughly 620KB when --dynamic is passed for npm packages and any typed code, or rejected at compile time with an SC code and a rewrite hint.
每个构造都会落入三个层级之一:默认静态编译;当为 npm 包和任何类型化代码传递 --dynamic 参数时,在约 620KB 的嵌入式 quickjs-ng 引擎中动态运行;或者在编译时被拒绝,并给出一个 SC 代码和重写提示。
A benchmark of scriptc 0.0.16 against Bun 1.3.12 and Node 24.18.0 recorded median CLI startup of 1.78ms versus 21.29ms for Bun and 61.78ms for Node, with idle memory of 1.9MiB for a framework free node:http server.
对 scriptc 0.0.16、Bun 1.3.12 和 Node 24.18.0 的基准测试显示,中位数 CLI 启动时间为 1.78 毫秒,而 Bun 为 21.29 毫秒,Node 为 61.78 毫秒,且一个无框架的 node:http 服务器的空闲内存为 1.9 MiB。
The same tests found Hono required --dynamic, pushing 62% of the server into QuickJS and cutting throughput to 18.4k requests per second against Bun's 70.5k.
同样的测试发现,Hono 需要 --dynamic 参数,导致服务器 62% 的部分进入 QuickJS,吞吐量降至每秒 18.4k 个请求,而 Bun 为 70.5k。
On Hacker News, one developer reported their results running about 7.5 times slower than Node 24:
在 Hacker News 上,一位开发者报告说,他们的运行结果比 Node 24 慢大约 7.5 倍:
Looking at the byte-array results (best case): scriptc is about 7.5x slower than Node 24, even after Claude tried making some scriptc-specific optimizations.
从字节数组结果(最佳情况)来看:即使 Claude 尝试进行了一些针对 scriptc 的优化,scriptc 仍比 Node 24 慢约 7.5 倍。
But the executable starts up 12x faster (1.5 ms vs 18.6 ms), uses 72x less memory (2.5 MiB vs 181 MiB), and is a single 370 KB executable with no runtime dependencies.
但可执行文件启动速度快了 12 倍(1.5 毫秒对比 18.6 毫秒),内存使用减少了 72 倍(2.5 MiB 对比 181 MiB),并且是一个单独的 370 KB 可执行文件,没有运行时依赖。
Filip Pizlo argued that using floats for all numbers and deferring integer inference skips "half the problem of fast JS", and that leaning on QuickJS is a poor fit for a performance project, since any is common enough that real programs will keep falling into the island.
Filip Pizlo 认为,对所有数字使用浮点数并推迟整数推断,跳过了“快速 JS 的一半问题”,而依赖 QuickJS 对于性能项目来说并不合适,因为 any 类型足够常见,以至于实际程序会不断落入那个孤岛。
Simon Willison noted that coding agents landed 918,000 lines in a single week, and also added that building small, fast binaries without writing C or Rust "seems like a valuable capability".
Simon Willison 指出,编码代理在一周内提交了 91.8 万行代码,并补充说,无需编写 C 或 Rust 就能构建小巧快速的二进制文件“似乎是一项有价值的能力”。
One developer found coverage produced hundreds of errors on every local project:
一位开发者发现,覆盖率在每个本地项目上都产生了数百个错误:
Despite the hate it is receiving, I thought lets test it at least, and tried it to any project that I have locally.
尽管它受到批评,但我想至少测试一下,于是对我本地的每个项目都试了试。
For every single of them the coverage generates hundreds of errors and so it is basically useless.
每一个项目都产生了数百个错误,所以它基本上毫无用处。
I get that I can write a project from scratch, don't use any third party library, and it'll compile to binary, but then why should I not use Rust, Go, Zig, D, C, V, Ada, C++, Nim, Swift, Kotlin Native, Haskell... literally anything designed to be compiled and compiled well?
我明白,我可以从头开始写一个项目,不使用任何第三方库,它就能编译成二进制文件,但那我为什么不用 Rust、Go、Zig、D、C、V、Ada、C++、Nim、Swift、Kotlin Native、Haskell……任何本就是为编译而设计且编译良好的语言呢?
A recurring worry is longevity, with commenters pointing at Vercel's zerolang, which stopped receiving commits weeks after launch.
一个反复出现的担忧是项目的持久性,评论者指出 Vercel 的 zerolang 在发布几周后就停止了提交。
Remo Jansen's attempt to compile the TypeScript 6 compiler itself failed at an internal compiler error, though he measured a 3.6ms cold start against Node's 48.9ms and a much slower 2.33s on compute.
Remo Jansen 尝试编译 TypeScript 6 编译器本身,结果因内部编译器错误而失败,不过他测得的冷启动时间为 3.6 毫秒(Node 为 48.9 毫秒),而计算时间则慢得多,为 2.33 秒。
The compiler needs Node.js 24 or newer, installs with npm install -g scriptc, and the limitations page documents deliberate divergences worth reading first: strings are stored as UTF-8, memory is reference counted rather than garbage collected, Object.keys reports declaration order, and process.argv[0] is "scriptc".
该编译器需要 Node.js 24 或更高版本,通过 npm install -g scriptc 安装,其限制页面记录了一些值得先读一读的有意差异:字符串以 UTF-8 存储,内存采用引用计数而非垃圾回收,Object.keys 按声明顺序报告,process.argv[0] 为 "scriptc"。
Dependency behaviour is covered in the npm dependencies guide, including the experimental --npm-static flag that compiles named packages out of the island.
依赖行为在 npm 依赖指南中有说明,包括实验性的 --npm-static 标志,它可以将指定的包编译出孤岛。
scriptc targets macOS, Linux, Windows and WASI Preview 1, is enforced by differential tests that compare stdout, stderr and exit codes byte for byte against Node, and remains explicitly experimental.
scriptc 的目标平台是 macOS、Linux、Windows 和 WASI Preview 1,通过差异测试来保证正确性——这些测试将 stdout、stderr 和退出码与 Node 逐字节比较——并且它明确仍处于实验阶段。
Documentation is at scriptc.dev.
文档位于 scriptc.dev。
阅读理解
1. According to the benchmark results, what is the main advantage of scriptc over Node and Bun?
2. What happens to a TypeScript construct that cannot be compiled statically and the --dynamic flag is not used?
3. What concern did commenters raise about scriptc's future?