mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-21 05:50:55 +08:00
* feat: support wasm32-wasi as a production target - Add production LLVM WASI codegen with a 32-bit ABI, coroutines, and dynamic modules - Integrate WASI builds and execution into the CLI with capability diagnostics - Add differential coverage and document the fourth production target Co-authored-by: Albert <57402359+bulatovv@users.noreply.github.com> * fix: address wasm target review findings * fix WASI guest paths and fetch alias detection * fix WASI async bridge and fetch detection --------- Co-authored-by: Albert <57402359+bulatovv@users.noreply.github.com>
120 lines
3.9 KiB
Markdown
120 lines
3.9 KiB
Markdown
# scriptc
|
|
|
|
scriptc compiles TypeScript and JavaScript to native executables and WebAssembly modules. It uses the TypeScript compiler for parsing and type checking, then emits LLVM IR for clang to compile. A readable C backend remains available for debugging.
|
|
|
|
Static builds include a small native runtime, but no Node or JavaScript engine. Code that cannot compile statically is reported as a diagnostic. For npm packages and `any`-typed code, `--dynamic` embeds [quickjs-ng](https://github.com/quickjs-ng/quickjs) explicitly.
|
|
|
|
scriptc is experimental and targets macOS, Linux, Windows, and WebAssembly via WASI Preview 1.
|
|
|
|
## Installation
|
|
|
|
The compiler requires Node.js 20 or newer and clang. The executables it produces do not require Node.
|
|
|
|
```console
|
|
$ npm install -g scriptc
|
|
```
|
|
|
|
## Build a program
|
|
|
|
Create `hello.ts`:
|
|
|
|
```ts
|
|
const who = process.argv.length > 2 ? process.argv[2] : "world";
|
|
console.log(`hello, ${who}`);
|
|
```
|
|
|
|
Compile and run it in one step:
|
|
|
|
```console
|
|
$ scriptc run hello.ts
|
|
hello, world
|
|
```
|
|
|
|
Or write a standalone executable:
|
|
|
|
```console
|
|
$ scriptc build hello.ts -o hello
|
|
$ ./hello ctate
|
|
hello, ctate
|
|
```
|
|
|
|
## Use Node APIs
|
|
|
|
Supported Node APIs compile to the native runtime. For example, `server.ts`:
|
|
|
|
```ts
|
|
import { createServer } from "node:http";
|
|
|
|
const server = createServer((req, res) => {
|
|
res.setHeader("content-type", "application/json");
|
|
res.end(JSON.stringify({ path: req.url }));
|
|
});
|
|
|
|
server.listen(8080, () => {
|
|
console.log("listening on http://localhost:8080");
|
|
});
|
|
```
|
|
|
|
```console
|
|
$ scriptc build server.ts -o server
|
|
$ ./server
|
|
listening on http://localhost:8080
|
|
```
|
|
|
|
## Check static coverage
|
|
|
|
`scriptc coverage` shows how much of a program can compile statically and gives a coded diagnostic for every dynamic or unsupported site.
|
|
|
|
```console
|
|
$ scriptc coverage hello.ts
|
|
|
|
statements analyzed 2
|
|
compile statically 2 (100%)
|
|
|
|
fully static — this program has no dynamic remainder.
|
|
```
|
|
|
|
## Build WebAssembly
|
|
|
|
WASI and other cross-target builds require Zig. Its bundled WASI libc produces a portable WASI Preview 1 module through the production LLVM backend:
|
|
|
|
```console
|
|
$ SCRIPTC_CC=zigcc SCRIPTC_TARGET=wasm32-wasi scriptc build hello.ts --no-keep-c -o hello.wasm >/dev/null
|
|
$ file hello.wasm
|
|
hello.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)
|
|
$ SCRIPTC_CC=zigcc SCRIPTC_TARGET=wasm32-wasi scriptc run hello.ts
|
|
hello, world
|
|
```
|
|
|
|
The WASI target supports the same executable language tiers as the native targets, including async/await, promises, generators, timers, stdin/readline events, callback and promise filesystem APIs, and `--dynamic`. APIs that require capabilities absent from portable WASI Preview 1—network sockets/fetch, child processes, OS signals, and filesystem watching—fail before linking with `SC3002`; sanitizer builds, native FFI, and library-mode archive builds are target diagnostics too. See [platform support](https://scriptc.dev/platforms) for the precise boundary.
|
|
|
|
## Use npm packages
|
|
|
|
Pass `--dynamic` to embed an npm package's JavaScript in the executable. The result does not read `node_modules` at runtime.
|
|
|
|
```ts
|
|
import pc from "picocolors";
|
|
|
|
console.log(pc.green("hello from scriptc"));
|
|
```
|
|
|
|
```console
|
|
$ npm install picocolors
|
|
$ scriptc build cli.ts --dynamic -o cli
|
|
$ ./cli
|
|
hello from scriptc
|
|
```
|
|
|
|
## Documentation
|
|
|
|
See the [quickstart](https://scriptc.dev/quickstart) and [CLI reference](https://scriptc.dev/cli) for the complete workflow. The docs also describe [npm dependencies](https://scriptc.dev/dependencies), [native FFI](https://scriptc.dev/ffi), [platform support](https://scriptc.dev/platforms), and the current [limitations](https://scriptc.dev/limitations).
|
|
|
|
## Development
|
|
|
|
```console
|
|
$ pnpm install && pnpm -r build
|
|
$ pnpm test:sandbox
|
|
```
|
|
|
|
The test corpus runs each program under Node and as a compiled native binary, then compares stdout, stderr, and exit codes byte for byte. The full gate also runs the corpus with AddressSanitizer and the runtime reference-count audit.
|