Vercel 发布 Scriptc:TypeScript 到原生代码编译器,二进制文件不包含 JavaScript 引擎

Hacker News Top 工具

摘要

Vercel Labs 发布了 Scriptc,这是一款编译器,能将普通 TypeScript 代码转换为小巧、快速的原生可执行文件,无需在二进制文件中包含 Node、V8 或任何 JavaScript 引擎。它支持 TypeScript 的大部分静态特性及 Node 的 API 接口。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/27 04:38

vercel-labs/scriptc

来源:https://github.com/vercel-labs/scriptc

scriptc

零运行时 TypeScript。 scriptc 将普通的 TypeScript 编译成小巧、快速的原生可执行文件——二进制文件中不含 Node、不含 V8、不含任何 JavaScript 引擎。

$ cat fib.ts
function fib(n: number): number {
  return n < 2 ? n : fib(n - 1) + fib(n - 2);
}
console.log(fib(30));

$ scriptc run fib.ts
832040

$ scriptc build fib.ts && ls -la fib
-rwxr-xr-x  178K  fib        # 自包含的原生二进制文件,启动约2ms

无需修改你的代码。无需注解、无需方言——你在 Node 上运行的同一种 TypeScript,由真正的 TypeScript 编译器进行类型检查,然后编译成原生代码。编译后的行为与 Node 逐字节一致。

安装

$ npm install -g scriptc

需要 clang(Xcode 命令行工具已预装)。macOS arm64 是主要平台;Linux 和 Windows 二进制文件通过交叉编译生成,每个平台都经过独立的差异测试通道验证。

理念:可见的静态性

大多数 TypeScript 的静态程度远超生态系统所假设的。scriptc 逐个构造地决定哪些可以编译为原生代码——并告知你:

$ scriptc coverage app.ts

  分析的语句数           4481
  静态编译的语句数       4451  (99%)

  阻碍项:
      ×2  作为值使用的可选参数函数       SC1090
      ×1  Promise.reject                SC2020

三个层次,始终清晰:

  1. 静态编译——原生代码,无引擎。这是默认模式,也是你未选择退出时的唯一模式。
  2. 动态运行--dynamic)——一个嵌入式 JavaScript 引擎(quickjs-ng (https://github.com/quickjs-ng/quickjs),约620KB)执行无法静态处理的部分:npm 依赖项附带的 JS、any 类型代码。每个返回静态代码的值都在运行时被验证——虚假的类型会抛出可捕获的 TypeError,而不是破坏内存。
  3. 拒绝——其他所有情况都会以特定错误码、代码帧和通常的重写提示失败。绝不会出现静默的错误编译。

编译范围

静态覆盖范围包括真实程序使用的语言和标准库:

  • 语言——支持单继承和真实动态分发(在可证明安全时去虚拟化)、具有 JS 捕获语义的闭包、泛型(单态化)、由 TypeScript 自身的窄化驱动的带标签值的受歧视联合、基于栈式纤程的异步/等待及 JS 精确调度、带 finally 的异常、解构、展开、可选/默认/剩余参数、getter/setter、字符串/数组/Map/Set 的迭代器、模板字符串、正则表达式(引擎是与 QuickJS 使用的相同 ECMAScript 精确字节码解释器,仅链接到使用正则的二进制文件中)。
  • 标准库——具有 UTF-16 精确语义的字符串、具有 JS 精确顺序和恒等性的数组/Map/Set、带运行时验证类型转换的 JSONMath、类型化数组和 Buffer、带类型化 catchError 层级。
  • Node 的 API 表面——fs(同步和 promise)、path(字节精确移植)、process、带管道流的 child_processoscryptourl/URLzlib、在无依赖事件循环上的定时器和信号处理器——以及服务器栈:nethttphttpstls(内联 mbedTLS)、dgramdnsfs.watchreadline。真实的代理服务器可以编译。
  • fetch 和 WHATWG 网页子集(流、HeadersAbortSignal)运行在同一原生网络/TLS 栈上——支持重定向、gzip、AbortSignal.timeout、Node 形状的错误原因;没有 libcurl,没有系统 HTTP 依赖。
  • npm 依赖项(配合 --dynamic)——包使用 Node 自身的算法解析,针对它们附带的 .d.ts 进行类型检查,它们的 JS 在构建时嵌入到二进制文件中。二进制文件在运行时永远不会读取 node_modules

程序针对 TypeScript 真正的 es2025 库(如果项目有 @types/node 则加上)进行类型检查,你的 tsconfig.json 控制检查器的严格程度。任何没有降级的代码都会生成精确的诊断,绝不会意外出错。

正确性

每次变更都运行两个强制机制:

  • 差异测试——每个语料库程序(800+ 个测试)同时在 Node 和原生二进制文件下运行;stdout、stderr 和退出码必须逐字节匹配。数字格式与 JS 精确一致(最短往返,在一百万个双精度浮点数上通过模糊测试与 Node 验证)。服务器通过实时客户端驱动程序对两种实现进行测试。
  • 内存安全通道——整个语料库在 AddressSanitizer 下重新运行,并附带引用计数审计;内存泄漏和释放后使用均视为构建失败。

与 Node 的故意差异(有几十个,主要涉及计时内部机制和错误对象属性)都已记录并编号;不会出现静默的差异。

性能

在 Apple M 系列上测量,与 Node、Go、Rust 和 Zig 上的相同工作负载对比(所有输出逐字节相同,已验证):

维度scriptc上下文
启动时间~2.4msNode:~47ms;与 Zig 相当,领先于 Go/Rust
二进制大小静态 170–200KB,--dynamic + 嵌入依赖约 3MBGo:~2MB;Node SEA:60–100MB
内存 (RSS)通常 1–4MBNode:67–116MB
运行时忠实于 JS 的 f64 语义;在大多数工作负载上与系统语言相竞争整数推断和所有权分析已在路线图上

逃生舱口

  • comptime(() => ...) 在构建时运行 TypeScript(在编译器内部的一个隔离 VM 中),并将结果以字面量的形式烘焙到二进制文件中。
  • 原生 FFI(--ffi 将仅含签名的 TypeScript 声明绑定到直接的 C ABI 调用,并链接清单中声明的归档文件、对象文件和系统库。边界是显式的且长度定界;请参见原生 FFI 指南 (https://scriptc.dev/ffi)。
  • --dynamic 嵌入引擎以处理 npm 依赖和 any 代码。scriptc coverage --dynamic 精确报告每条语句在何处运行,以及剩余的阻碍项。静态仍然是默认选项:二进制文件绝不会悄无声息地增长出引擎。
  • 检查类型转换——JSON.parse(...) as Config 会在运行时插入验证,如果类型不符则抛出可捕获的错误,并指明违规路径(例如 expected number at $.port, got string)。TypeScript 的 as 是一种承诺;scriptc 会验证它。

架构

flowchart LR
    TS[TypeScript] -->|tsc: parse + typecheck| L[lowering]
    L --> IR[typed IR]
    IR --> C[C]
    C -->|clang| BIN[native executable]
  • packages/compiler —— 前端(tsc API → IR)、包含验证器/序列化器的 IR、LLVM 和 C 后端。IR 是两端之间的唯一接口;LLVM 是默认代码生成器(对于其层级之外的程序有透明回退),C 是永久参考后端(可通过 --backend c 输出可读的、带源代码行注释的代码)。
  • packages/runtime —— C 运行时:带循环垃圾收集器的引用计数值、栈式纤程和事件循环(kqueue)、服务器栈、JS 精确数字格式化。特性单元按链接门控:二进制文件只为使用的功能付费。
  • packages/cli —— scriptc build | run | coverage

开发

$ pnpm install && pnpm build
$ pnpm test                      # 差异测试语料库 + 诊断快照
$ SCRIPTC_SAN=1 pnpm test        # 在 ASan + RC 审计下的相同语料库
$ pnpm scriptc build x.ts --emit-ir   # 保留 .scriptc/x.c 和 x.ir.json

每个特性都附带差异测试;两条通道均为绿色才能合并。

相似文章

TypeScript 7

Hacker News Top

TypeScript 7 是一个重大版本,它将编译器用 Go 语言重写,实现了 8-12 倍的构建速度提升,同时保持完全兼容性,现已在 npm 上可用。

microsoft/TypeScript

GitHub Trending (daily)

TypeScript 是一种用于大规模 JavaScript 应用的语言,它增加了可选类型。该仓库托管了 TypeScript 编译器及相关工具。