README 的“Build a program”和“Use Node APIs”章节展示了 `scriptc build`、`./hello` 和 `node:http`。
scriptc:把 TypeScript 编译成原生程序和 WebAssembly
一个把 TypeScript 编译成原生程序或 WASI 模块的实验性工具,产物运行时不依赖 Node。
🧭 决策指南
为什么现在热: 无法从材料判断
适合,如果你
-
你要把 `hello.ts` 或 Node.js `node:http` 服务编译成不依赖 Node 的可执行文件。
-
你需要把 TypeScript 输出为 `.scriptc/` 中的 IR、C、LLVM IR、汇编或对象文件。README 的“Build a program”章节列出了 `--emit=ir|c|llvm|asm|obj` 及对应文件。
-
你需要将 npm 包如 `picocolors` 嵌入可执行文件,而不是运行时读取 `node_modules`。README 的“Use npm packages”章节要求使用 `--dynamic`,并明确写出运行时不读取 `node_modules`。
-
你的目标是 WASI Preview 1,并且可以安装 Zig、使用 `SCRIPTC_CC=zigcc`。README 的“Build WebAssembly”章节给出了 `SCRIPTC_TARGET=wasm32-wasi` 和 Zig 命令。
不适合,如果你
-
你的 WASI 程序依赖网络 sockets、fetch、child processes、OS signals 或 filesystem watching。README 的“Build WebAssembly”章节说明这些能力在 WASI Preview 1 中会以 `SC3002` 在链接前失败。
-
你需要把 `--emit=obj` 直接当作独立库使用。README 明确说明 `--emit=obj` 是 relocatable program object,不是 standalone library,并含未定义 `scr_*` 引用。
-
你的项目要求成熟稳定的生产级编译器,而不是 experimental 的 v0.1.7 项目。README 写明 scriptc is experimental;发布信息显示最新版本为 v0.1.7。
-
你只能使用 Node.js 23 或更早版本。README 的“Installation”章节要求 Node.js 24 or newer。
前置条件
- Node.js 24 or newer。
- `--emit=ir|c|llvm` 只需要 Node。
- `--emit=asm|obj` 使用 scriptc 在受支持 macOS、Linux、Windows 主机上安装的 matching optional platform helper。
- 普通 LLVM-tier executable build 需要 platform linker driver 和 SDK/sysroot。
- WASI 和其他 cross-target build 需要 Zig,并确保 `zig` 位于 `PATH`。
- `--dynamic` 用于 npm packages 和 `any`-typed code,并显式嵌入 `quickjs-ng`。
第一步命令(README 原文)
$ npm install -g scriptc
要注意
-
`SCRIPTC_CC=zigcc` 是调用 Zig `cc` 子命令的选择器,不是独立可执行文件。README 的“Build WebAssembly”章节对 `SCRIPTC_CC=zigcc` 有明确说明。
-
macOS 15+ arm64 的 helper 产物使用 `arm64-apple-macosx14.0.0` deployment target。README 的“Build a program”章节说明了 helper 运行平台和 deployment target。
-
WASI 的 sanitizer、native FFI 和 library-mode archive builds 会成为 target diagnostics。README 的“Build WebAssembly”章节列出了这些 WASI 限制。
-
外部 object consumption 仍是 experimental,需要 `--print=native-link-info` 生成带 ABI marker 的 JSON recipe。README 的“Build a program”章节明确称 external object consumption 为 experimental。
材料未说明
- README 未给出不同 TypeScript 项目或 Node.js API 的完整支持清单。
- README 未提供 scriptc 与 Node.js、TypeScript 编译器或其他 native compiler 的性能基准。
- README 未说明 `--dynamic` 嵌入 `quickjs-ng` 后的产物体积和运行时开销。
- README 未给出 macOS、Linux、Windows 各版本的完整兼容矩阵。
- README 未说明 v0.1.7 之后的 API、CLI 参数和兼容性承诺。
- README 未说明 native FFI 的具体 ABI、平台边界和可用示例范围。
💡 深度解析
6
不适合
我想把 TypeScript 代码编译成可被 C 驱动或 Apple linker 消费的对象文件;我能否把 `--emit=obj` 当作独立库直接链接?
适合读者: 正在构建 C 驱动或直接 Apple linker 集成的系统开发者,需要消费 scriptc 的 `--emit=obj` 目标文件,并接受 native FFI 和 external object consumption 仍属实验性
不适合把 --emit=obj 当作独立库直接链接;README 明确说它是 relocatable program object,不是 standalone library。
- 该对象含有未定义的
scr_*runtime 引用,并要求scr_runtime_abi_v2marker,因此还需要匹配的 runtime 和 ABI 配置。 - 外部对象消费仍是 experimental;README 要求使用
--print=native-link-info生成 versioned JSON recipe。 - recipe 会记录 target、
mainentry、准确的@scriptc/runtimesource pack、系统库、FFI inputs 和 ABI marker,不能凭隐藏缓存路径拼链接命令。 - 如果真正需要自包含 archive,应使用
scriptc build --lib --profile ...;但 WASI 目标又把 library-mode archive 列为诊断项。
因此,C-driver 或 direct Apple-linker 集成可行,但必须按 recipe 完整组装,而不是把 .o 当普通库。
- Build a program:`--emit=obj` writes a relocatable program object, not a standalone library
- Build a program:It has undefined `scr_*` runtime references and a required `scr_runtime_abi_v2` marker
- Build a program:Use `--print=native-link-info` to emit ... a versioned JSON recipe
- Build a program:`scriptc build --lib --profile ...` remains the self-contained archive interface
适合
我的 TypeScript 工具目标是 `wasm32-wasi`,构建机可以安装 Zig,功能只需要 stdin/readline、Promise、定时器和文件系统;scriptc 是否适合?
适合读者: 需要把 TypeScript CLI 部署到 WASI Preview 1 的工具开发者,构建环境可以安装 Zig,但程序不能使用网络、子进程、OS signals 或文件监听
适合,前提是程序严格遵守 WASI Preview 1 的能力边界。
- README 要求 WASI 和其他 cross-target builds 使用 Zig,并通过 bundled WASI libc 生成 WASI Preview 1 module。
- README 明确列出 async/await、promises、generators、timers、stdin/readline events,以及 callback 和 promise filesystem APIs 为支持能力。
- 网络 sockets/fetch、child processes、OS signals 和 filesystem watching 会在链接前以
SC3002失败;你的约束正好避开这些限制。 - 构建命令需要
SCRIPTC_CC=zigcc、SCRIPTC_TARGET=wasm32-wasi,并要求zig在 PATH 中;zigcc不是独立可执行文件。
如果工具还需要 native FFI、sanitize 或 library-mode archive,WASI 目标同样会拒绝这些能力。
- Build WebAssembly:WASI and other cross-target builds require Zig
- Build WebAssembly:The WASI target supports ... async/await, promises, generators, timers, stdin/readline events, callback and promise filesystem APIs
- Build WebAssembly:network sockets/fetch, child processes, OS signals, and filesystem watching fail ... with `SC3002`
- Build WebAssembly:`$ SCRIPTC_CC=zigcc SCRIPTC_TARGET=wasm32-wasi scriptc build hello.ts --no-keep-c -o hello.wasm >/dev/null`
$ SCRIPTC_CC=zigcc SCRIPTC_TARGET=wasm32-wasi scriptc build hello.ts --no-keep-c -o hello.wasm >/dev/null
适合
我的 TypeScript 项目包含 any 和 npm 依赖,我想先知道哪些语句能静态编译、哪些位置必须动态执行;scriptc 能提供逐位置判断吗?
适合读者: 需要先判断现有 TypeScript 项目能否静态编译的维护者,项目可能包含 any、npm 依赖和动态 JavaScript 行为,希望获得逐位置诊断而不是直接猜测
适合,coverage 就是为这个决策设计的诊断入口。
- README 说明
scriptc coverage会显示程序能静态编译的比例,并为每个 dynamic 或 unsupported site 给出 coded diagnostic。 - 示例对
hello.ts输出statements analyzed、compile statically和fully static,能先确认代码是否存在动态剩余。 - README 同时明确:npm packages 和 any-typed code 通常需要
--dynamic,因此 coverage 结果可以帮助你判断是调整源码、接受动态运行时,还是放弃原生路径。 - 该命令不会自动证明完整 Node 兼容性;项目仍处于 experimental 阶段,且诊断范围受目标平台和 runtime 支持影响。
先用 coverage 获取代码位置和诊断,再决定纯静态或嵌入 quickjs-ng 的构建方式,是 README 明确支持的工作流。
- Check static coverage:`scriptc coverage` shows how much of a program can compile statically
- Check static coverage:gives a coded diagnostic for every dynamic or unsupported site
- README:For npm packages and `any`-typed code, `--dynamic` embeds quickjs-ng explicitly
- README:scriptc is experimental
$ scriptc coverage hello.ts
适合
我有一个类型明确的 TypeScript CLI,构建机使用 Node.js 24+,目标是 macOS 15+ arm64;我能否用 scriptc 生成一个部署时不依赖 Node 的单文件程序?
适合读者: 维护 TypeScript CLI、构建环境要求 Node.js 24+、希望把 macOS 15+ arm64 上的工具交付为不依赖 Node 的独立可执行文件的开发者
适合,因为 README 明确支持把 TypeScript 编译为独立原生可执行文件,而且生成的 executable 不需要 Node。
- 安装阶段要求 Node.js 24 或更高版本,但这是编译器的要求,不是最终程序的运行要求。
- macOS 15+ arm64 的普通 LLVM-tier executable 使用 bundled helper 和 precompiled runtime pack;clang 只作为平台 linker driver,不负责编译生成的程序或 runtime C。
- 静态构建包含较小的 native runtime,不包含 Node 或 JavaScript engine;类型明确、没有动态剩余的 CLI 最符合这条路径。
- README 已给出
scriptc build hello.ts -o hello和./hello的独立程序流程。
不过 Node API 覆盖和动态特性仍有限,不能把它当作完整 Node.js 替代品。
- Installation:The compiler requires Node.js 24 or newer
- Installation:The executables it produces do not require Node
- README:On macOS 15+ arm64, ordinary LLVM-tier executables use scriptc's bundled helper and precompiled runtime pack
- Build a program:`$ scriptc build hello.ts -o hello`
$ scriptc build hello.ts -o hello
视情况
我的 TypeScript CLI 使用 picocolors 这类 npm 包,代码中也可能有 any;我能否在不让最终程序读取 node_modules 的前提下用 scriptc 打包?
适合读者: 维护依赖 picocolors 等 npm 包的 TypeScript CLI、希望发布时不携带 node_modules、但可以接受嵌入 QuickJS 动态运行时的开发者
视情况,但如果接受 QuickJS 运行时,README 给出了明确的兼容路径。
- README 指出 npm packages 和 any-typed code 应使用
--dynamic;该模式会显式嵌入 quickjs-ng。 - 生成物运行时不读取
node_modules,因此适合希望交付单个 CLI 的场景。 - 代价是它不再是纯静态原生程序:JavaScript 执行能力来自嵌入的 QuickJS,运行时体积、性能和行为兼容性不能按静态路径理解。
- 项目仍处于 experimental 阶段,且 README 没有承诺所有 npm 包、原生扩展或 Node 专属行为都能工作。
README 的示例就是安装 picocolors 后执行 scriptc build cli.ts --dynamic -o cli,因此这类 CLI 可以优先沿用该路径。
- README:For npm packages and `any`-typed code, `--dynamic` embeds quickjs-ng explicitly
- Use npm packages:The result does not read `node_modules` at runtime
- Use npm packages:`$ scriptc build cli.ts --dynamic -o cli`
- README:scriptc is experimental
$ scriptc build cli.ts --dynamic -o cli
视情况
我维护一个使用 `node:http`、Promise 和文件系统 API 的 TypeScript 服务;在 Linux 或 macOS 上,我能否把它编译成不依赖 Node 的原生服务?
适合读者: 维护使用 node:http、文件系统和异步 API 的 TypeScript 服务,希望在 Linux 或 macOS 上减少 Node 部署依赖的服务开发者
视情况,README 已证明部分 Node API 可走 native runtime,但是否适合取决于服务实际使用的 API 边界。
Use Node APIs示例直接用node:http创建 HTTP 服务,并通过scriptc build server.ts -o server生成可执行文件。- 项目洞察列出已支持的文件系统、异步、Promise、生成器、定时器和 stdin/readline 能力,但支持范围取决于目标平台。
- 静态构建不带 Node 或 JavaScript engine;未实现或无法静态编译的代码会产生诊断。
- 普通 LLVM-tier executable 仍需要平台 linker driver 和 SDK/sysroot;预编译 runtime pack 并不消除这些构建条件。
因此,受控的 HTTP 服务可能合适,但依赖完整 Node 生态、动态加载或未覆盖 API 的服务不应直接迁移。
- Use Node APIs:`import { createServer } from "node:http";`
- Use Node APIs:`$ scriptc build server.ts -o server`
- Installation:Ordinary LLVM-tier executable builds need a platform linker driver and SDK/sysroot
- README:Code that cannot compile statically is reported as a diagnostic
$ scriptc build server.ts -o server
✨ 核心亮点
-
支持 IR、C、LLVM IR、汇编和原生可执行文件
-
静态产物运行时不需要 Node 或 JavaScript 引擎
-
可用 Zig 构建 WASI Preview 1 模块
-
项目明确标注为 experimental,当前 v0.1.7
🔧 工程化
-
用 TypeScript 编译器解析并检查类型,输出 typed IR、C、LLVM IR 与原生产物。
-
`--dynamic` 可把 npm 包 JavaScript 和 `quickjs-ng` 嵌入可执行文件。
-
`scriptc coverage` 为动态或不支持代码生成逐点诊断。
⚠️ 风险
-
README 明确称 scriptc 为 experimental,项目仅有 4 位贡献者和 5 个版本。
-
`any`、npm 包和无法静态编译的代码需要 `--dynamic` 或会产生诊断。
-
WASI Preview 1 不支持网络、子进程、OS 信号和文件监听。
-
`--emit=obj` 不是独立库,含未定义 `scr_*` 运行时引用。
👥 适合谁?
-
需要把 TypeScript CLI 或 Node.js API 编译成无 Node 运行时程序的开发者。
-
目标为 macOS、Linux、Windows 或 WASI Preview 1 的原生编译实验者。
-
需要 `scriptc coverage` 检查静态覆盖率和动态代码边界的 TypeScript 团队。