ByteNoteByteNote
TypeScript 不止能跑在 Node:Vercel 实验编译器直出原生二进制
字

字节笔记本

2026年9月29日 · 约 4 分钟读完

TypeScript 不止能跑在 Node:Vercel 实验编译器直出原生二进制

API中转
¥120

TypeScript 写完还要拖着一个 Node 运行时分发?Vercel Labs 的实验项目 scriptc 给出了另一条路:把 TypeScript/JavaScript 直接编译成类型化 IR、可读 C、LLVM IR、汇编、目标文件,一路直到不依赖 Node 的原生可执行文件和 WebAssembly 模块。项目目前 5.7 千星,Apache-2.0 协议,npm install -g scriptc 一条命令装好。

scriptc 的产出阶梯:每一级都停在可读产物上

项目简介

scriptc 是 Vercel Labs 的公开实验(明确标注 experimental),前端复用 TypeScript 编译器做解析和类型检查,后端自己走完整条编译链。它最讲究的一点是每一级产物都可读、可停留:--emit=ir|c|llvm|asm|obj 想停在哪一级就停在哪一级,产物累积在 .scriptc/ 目录里,你可以只看生成的 C 长什么样,也可以一路走到原生二进制。

产物侧的边界划得很诚实:静态构建包含一个小型原生运行时,不带 Node 和任何 JavaScript 引擎;凡是静态编译不了的代码(npm 包、any 类型的动态代码)不会静默失败,而是作为诊断明确报出来。确实需要动态能力时,加 --dynamic,它会显式内嵌 quickjs-ng 引擎作为兜底。

支持面:macOS、Linux、Windows 和 WASI(WebAssembly)四个目标;macOS 15+ arm64 上有捆绑 helper 和预编译运行时包,普通可执行文件构建不需要 clang 参与编译(它只当链接驱动)。编译器本体需要 Node 24+,但编译出来的产物不再需要 Node。

quickjs-ng:--dynamic 模式的显式回退引擎

快速上手

bash
npm install -g scriptc

写一个 hello.ts:

ts
const who = process.argv.length > 2 ? process.argv[2] : "world";
console.log(`hello, ${who}`);

两种最常用的姿势:

bash
scriptc run hello.ts          # 编译并直接运行
scriptc build hello.ts -o hello  # 产出独立可执行文件
./hello scriptc               # hello, scriptc

更惊喜的是 Node API 也能编:用 node:http 写的 createServer 会被编译到原生运行时上,构建出的 server 二进制直接监听端口——这意味着简单 HTTP 服务也可以脱离 Node 分发。

想研究中间产物就沿阶梯逐级 --emit,或者用 --print=native-link-info 拿到一份带版本号的 JSON 链接配方(目标三元组、入口、运行时包、所需系统库、ABI 标记),外部 C 工具链按配方消费,全程不依赖隐藏缓存路径。

适合谁用

写 CLI 工具的开发者:分发给没有 Node 环境的用户时,"一个原生文件"比"先装 Node 再 npm i"体验好一截。

关心启动速度和分发体积的人:静态编译产物没有 JS 引擎启动开销,具体数字建议自己量——项目仍处实验期,官方没有承诺性能数据。

想读编译器的人:每一级产物都可读这条设计,让它成了少见的"能看到 TS 变成什么样 C"的活教材。

两句实话:实验项目,别把生产关键路径押上去;any 和 npm 生态是静态化的天敌,遇到诊断信息说明你的代码依赖动态能力,该回退 --dynamic 就回退。对"TypeScript 的终点只有 Node"这个默认假设来说,scriptc 至少把它变成了一个可以动手验证的问题。

相关文章

分享: