vercel-labs/scriptc · 上手攻略
- 仓库:vercel-labs/scriptc
- 链接:https://github.com/vercel-labs/scriptc
- 分类:工具链 · 编译器
- 作者:Tom
- 更新:2026-08-10
这是什么
scriptc 是 Vercel Labs 出品的 TypeScript-to-Native 编译器,将普通 TypeScript 代码直接编译为独立的原生可执行文件(ELF/mach-O),运行时无需 Node.js 或任何 JavaScript 引擎。号称"zero-runtime TypeScript",实测 startup 仅约 2.4ms(Node.js 约 47ms),二进制大小 170–200KB(纯静态),内存 RSS 仅 1–4MB(Node.js 动辄 67–116MB)。
核心思路:静态分析 + 按需降级。scriptc 逐构造(construct by construct)判断代码能否编译为原生码——能编的编,不能编的自动降级到嵌入式 quickjs-ng 引擎(~620KB),既不默默出错,也不静默膨胀。
解决什么问题
- CLI 工具的分发噩梦:传统 Node.js CLI 分发需要用户装 Node、npm install、找对版本。用 scriptc 编译后交付一个 170KB 的原生二进制,点开就跑。
- 轻量脚本的冷启动问题:Node.js 冷启动 40ms+,scriptc ~2ms,适合对延迟敏感的脚本和 serverless 函数入口。
- 真正的"一份代码到处跑":同一套 TypeScript,编译出 macOS ARM64/Linux x64/Windows 原生二进制,无需 Docker 或 Node 版本管理。
快速安装
# 全局安装 CLI(需要 clang,macOS 已预装 Xcode Command Line Tools)
npm install -g scriptc
# 或者用 pnpm(项目内)
pnpm add -D scriptc
依赖:clang(macOS: xcode-select --install;Linux: apt install clang 或发行版对应包;Windows: WSL 或交叉编译)。
核心用法
运行(边编译边跑)
# 编译 + 执行,输出直接打印
scriptc run fib.ts
构建(产出原生二进制)
# 构建原生可执行文件
scriptc build fib.ts && ls -la fib
# -rwxr-xr-x 178K fib ← 独立原生二进制,约 2ms 启动
# 查看覆盖率报告(哪些代码可静态编译,哪些需要动态引擎)
scriptc coverage app.ts
# statements analyzed 4481
# compile statically 4451 (99%)
# blockers:
# ×2 functions with optional parameters as values SC1090
# ×1 Promise.reject SC2020
动态模式(含 npm 依赖)
# 默认静态编译;当代码含 npm 依赖或 any 类型时,用 --dynamic 嵌入 quickjs-ng 引擎
scriptc build app.ts --dynamic
# 产物 ~3MB(含嵌入式 JS 引擎),但依然零 Node 依赖
Native FFI(调用 C 库)
# 用 --ffi 绑定 C ABI,声明型调用系统库
scriptc build app.ts --ffi
# 参考文档:https://scriptc.dev/ffi
构建缓存
# 默认开启内容寻址缓存,只重编译变化部分
# 禁用缓存
SCRIPTC_NO_CACHE=1 scriptc build app.ts
# 指定缓存目录
SCRIPTC_CACHE_DIR=/tmp/scriptc-cache scriptc build app.ts
编译后端(可选)
# 默认 LLVM 后端;C 后端(可读、带源码注释)
scriptc build app.ts --backend c # 产出 .scriptc/x.c 可供阅读
开发者命令
# 编译并保留中间产物(IR + C)
scriptc build x.ts --emit-ir
# 生成 .scriptc/x.c 和 x.ir.json
# 本地开发
pnpm install && pnpm build
pnpm test # 差异测试 corpus + 诊断快照
SCRIPTC_SAN=1 pnpm test # AddressSanitizer + RC 审计
典型适用场景
| 场景 | 为什么 scriptc 合适 |
|---|---|
| 轻量 CLI 工具 | 170KB 二进制替代 npm 全局包,用户无需装 Node |
| 边缘函数 / CDN edge | ~2ms 冷启动,适合 Vercel Edge Functions 类场景 |
| 嵌入式 / IoT | RSS 仅 1–4MB,远低于 Node 的 67MB+ |
| 构建脚本(build scripts) | 零依赖、跨平台,写 TypeScript 产出原生脚本 |
| 带 npm 依赖的工具 | --dynamic 自动嵌入 quickjs-ng,无需 Node 运行时 |
坑与注意
- macOS ARM64 是主平台:Linux/Windows 交叉编译有专门测试 lane,但 macOS 体验最成熟;ARM Mac 优先。
- --dynamic 产物有 Embed:加了 npm 依赖后二进制跳到 ~3MB,仍然比 Node SEA(60–100MB)小一个数量级,但不再是"170KB 极限"。
- 编译器仍需运行:每次
scriptc build都需要 Node.js 在构建机器上运行,只是产物不需要。 - 未支持的部分会显式报错:SC1090(optional parameter as value)、SC2020(Promise.reject)等都有精确错误码 + 重写提示,不会静默降级。
- 内存安全依赖 C 运行时:quickjs-ng 引擎本身不是内存安全的;scriptc 用 AddressSanitizer 做 RC 审计,但生产环境仍需注意。
- 整数推断和所有权分析尚未实现(Roadmap 上),追求极致数字性能的场景暂不适用。
- 版本标注:README 未标具体发布版本,v1.0 尚未 release(2026-08-10 状态)。⚠️ 生产使用前请自行确认 release tag。
与同类对比
| 特性 | scriptc | Bun (bundle) | Go/Rust 手动重写 | pkg / nexe |
|---|---|---|---|---|
| 语言 | TypeScript 原生编译 | TypeScript 运行时 | 需重写 | Node.js 打包 |
| 二进制大小 | 170–200KB | N/A (运行时) | ~1–2MB | 60–100MB |
| 冷启动 | ~2ms | ~10ms | ~1ms | ~40ms |
| 内存 RSS | 1–4MB | 20–50MB | 1–5MB | 60–100MB |
| npm 生态 | ✅ --dynamic | ✅ | ❌ | ✅ |
| 零 JS 引擎 | ✅ 静态编译 | ❌ | ✅ | ❌ |
| 成熟度 | 早期(v1 未 release) | 稳定 | — | 稳定 |
一句话:如果你想用 TypeScript 写一个零依赖、分发简单的原生工具,scriptc 是目前最接近"一份 TS → 最小原生二进制"的方案;如果需要完整 Node.js 生态(网络、文件系统深度集成),Bun 或传统 Node 方案更稳。
一句话推荐结论
写 TypeScript,分发原生二进制——scriptc 把 TypeScript 编译器前端(tsc)直连到 clang,用多少编译多少,99% 的静态代码零运行时依赖,是 CLI 工具和边缘计算场景的轻量级新选择。注意 v1 尚未正式发布,生产引入前建议确认最新 release。
来源:GitHub README (https://github.com/vercel-labs/scriptc) · 官方文档 (https://scriptc.dev/ffi)