# watr [![npm](https://img.shields.io/npm/v/watr?color=white)](https://npmjs.org/watr) [![test](https://github.com/dy/watr/actions/workflows/test.js.yml/badge.svg)](https://github.com/dy/watr/actions/workflows/test.js.yml) [![spec](https://github.com/dy/watr/actions/workflows/spec.yml/badge.svg)](https://github.com/dy/watr/actions/workflows/spec.yml) _Light & fast WAT compiler_ * [feature](https://webassembly.org/features/?categories=tools) & [spec](https://webassembly.github.io/spec/core/text/index.html)-complete, zero deps * [compile](./docs.md#compilesource), [polyfill](./docs.md#polyfillast-options), [optimize](./docs.md#optimizeast-options), [parse](./docs.md#parsesource-options), [prettify](./docs.md#printtree-options), [minify](./docs.md#printtree-options) * instant wasm, JS interop, CLI, [source maps](./docs.md#source-maps), clear errors **[site](https://dy.github.io/watr)**  /  **[docs](./docs.md)**  /  **[playground](https://dy.github.io/watr/play/)** ## Usage ```js import watr, { compile, parse, print } from 'watr' // compile to binary const src = '(func (export "f") (result f64) (f64.const 1))' const binary = compile(src) const module = new WebAssembly.Module(binary) const { f } = new WebAssembly.Instance(module).exports // optional, heavy transforms ship as separate entries — compose them import optimize from 'watr/optimize' // fold constants, treeshake, eliminate dead code … import polyfill from 'watr/polyfill' // newer features → MVP compile(optimize(polyfill(src))) // parse parse('(i32.const 42)') // ['i32.const', '42'], with a .loc source offset parse('(i32.const 42)', { loc: false }) // omit offsets for generated WAT // print print('(module(func(result i32)i32.const 42))') // (module\n (func (result i32)\n ... // instant wasm function const { add } = watr`(func (export "add") (param i32 i32) (result i32) (i32.add (local.get 0) (local.get 1)) )` add(2, 3) // 5 // instant wasm: interpolate, auto-import ... const { test } = watr`(func (export "test") (call ${console.log} (i32.const 42)))` test() // logs 42 ``` ## CLI ```sh npx watr input.wat # → input.wasm npx watr input.wat -o out.wasm # custom output npx watr input.wat --print # pretty-print npx watr input.wat --minify # minify npx watr input.wat --optimize # fold, treeshake, inline, coalesce, … npx watr input.wat --polyfill # newer features → MVP npx watr input.wat --source-map # + input.wasm.map from ;;@ file:line:col comments ``` ## Metrics * **watr** — ~44 KB minified (~14 KB gzipped), 3,123 op/s * [spec/wast.js](https://github.com/WebAssembly/spec) — 216 KB, 1,509 op/s * [wabt](https://github.com/WebAssembly/wabt) — 282 KB, 859 op/s * [binaryen](https://github.com/WebAssembly/binaryen) — 1,100 KB, 473 op/s * [wat-compiler](https://github.com/stagas/wat-compiler) — ~152 KB (+ wabt dep), 355 op/s ### Optimizer vs binaryen (wasm-opt 128) | | size (total) | time (batch) | footprint | |---|---|---|---| | **watr/optimize** | **19,734 B** | **~110 ms** in-process | 149 KB min (46 KB gz) | | `wasm-opt -Oz` | 19,852 B | 990 ms CLI | ~1.1 MB js / native binary | | `wasm-opt -O3` | 22,302 B | — | — | Measured on [test/example](./test/example) (21 modules, `optimize(src)` defaults vs `wasm-opt -all`).
Smaller than `-O3` on every module and than `-Oz` in aggregate (19,734 vs 19,852 B); ties or beats `-Oz` on 18 of 20 files. On a 5.5 MB module watr's output is 1.7% SMALLER than `-Oz` (261,345 vs 265,977 B — cross-function outlining); binaryen's native core is faster there (0.44 s vs ~2.6 s optimize + 0.19 s compile) — watr's edge is output size, batch/in-process use with no process spawn, and a ~25× smaller footprint.
## Used by * [jz](https://github.com/dy/jz) – minimal static JS subset

ॐ