中文版 · Docs site · Samples · Changelog
winterjs2 is a Bun-like JavaScript runtime on Mozilla SpiderMonkey — one binary that runs JS files, package.json scripts, tests, linters and static/dynamic HTTP services, with node: compatibility tracking Bun's height.
./target/debug/winterjs2 --run sample/http/server-client.js
./target/debug/winterjs2 --eval 'await (await fetch("data:text/plain,hi")).text()' # → hiNote: winterjs2 shares only the "Winter" name with wasmerio/winterjs (a WinterCG server, now deprecated). This project is a general-purpose JS runtime in the Bun/Node lane — rebuilt from scratch on
servo/mozjs, no server framework inside.
REPL — Tab completion with an inline docs pane (like Ruby's irb; .doc <name> prints the full page)
Engine versions at your fingertips — WinterJS2.versions.mozjs is the pinned SpiderMonkey (Gecko 153)
Vue 3 + Vite driven by winterjs2 — winterjs2 -r build / winterjs2 -r dev, Vue DevTools live in the browser
WinterJS2.media + utilities — decode FLAC from an MP4, encode AV1, draw a QR code in the terminal (Linux x86_64 build)
export SDKROOT="$(xcrun --show-sdk-path)" # macOS, every new shell
export LIBCLANG_PATH="/opt/homebrew/opt/llvm/lib" # for bindgen
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
cargo build
./target/debug/winterjs2 --eval '40 + 2' # → 425-minute path: English / 中文 ·
128 runnable examples in sample/ (one per module, all offline-capable).
One invocation runs exactly one action; modifiers only work with their action
(--port → --serve, --filter → --test, --watch → --test/--run/--serve,
--schema → --config):
| Flag | Effect |
|---|---|
-r/--run <file|script> |
Run a JS file or a package.json script (JS bins re-execute through winterjs2, zero node; --watch re-runs on change) |
-e/--eval <code> |
Evaluate inline JS, print the completion value |
-t/--test [paths] |
Run test files (auto-discovery, --filter/--watch) |
-s/--serve [dir] |
Serve static + JS fetch handler + WebSocket over H1/H2/H3 (--watch restarts on change) |
-b/--db <file> [--exec <sql>] |
Inspect a turso/SQLite database file (default lists tables); storage files use --storage-path |
--repl |
Interactive REPL |
-a/--add, -i/--install, -R/--remove, -U/--uninstall, -p/--publish, --login, -u/--upgrade, -I/--init |
Package lifecycle (npm registry) |
-L/--lint, -f/--fmt |
Forward to oxlint/oxfmt |
-c/--config, -C/--completions, -m/--man, -v, -l/--lang |
Config/help/i18n/logging |
-hide_banner |
Hide the startup banner, like ffmpeg does (stderr, auto-skipped when not a TTY) |
-ascii_banner |
Force the ASCII banner even on graphics-capable terminals |
Full reference: CLI (EN) / CLI (中文).
winterjs2 links Mozilla SpiderMonkey (mozjs =0.26.0, Gecko 153, pinned) through
servo/mozjs and implements everything else — event loop, loader, Web/Node
builtins, node: compatibility modules — in pure Rust. unsafe lives only at the mozjs
boundary (rooting, AutoRealm, FFI); JS runs on a dedicated thread and Rust
sides talk to it through message queues, never by sharing &mut JSContext.
Goal: everything in Bun's bundled node test list works; semantics follow Node
(lib/ source + test/parallel assertions). Per-module status, samples and
known deviations live in the API reference:
| Area | Status | Notes |
|---|---|---|
fs/net/http/https/http2/tls/dgram/dns |
✅ Stable | streaming bodies, keep-alive, H2C, UDP loopback |
crypto/zlib/buffer/stream/events/timers |
✅ Stable | AEAD ciphers, brotli, WHATWG streams |
child_process/cluster/worker_threads/vm/module/test |
✅ Stable | thread-based cluster/workers |
sqlite (node: + bun:sqlite), quic, readline/repl/tty |
✅ / 🔶 | quic handshake on loopback times out (known issue, under investigation) |
storage / localStorage (WinterCG own) |
✅ Stable | turso single-file KV (--storage-path, default ./winterjs2-storage.db); inspect via -b/--db |
v8/inspector/trace_events/domain |
🔶 Bridge | intentionally reduced (heap numbers are engine-specific) |
wasi, sea |
❌ | out of scope by design |
Web globals (fetch, URL, TextEncoder, Web Streams, WebCrypto, WebSocket,
structuredClone, …) ship alongside — see the API reference.
- Cross-engine numbers are not comparable (
v8heap stats,allocUnsafeis zero-filled). structuredClonecovers plain data (Date/Map/Set come back as plain objects).node:quicsession handshake on loopback times out;node:httpscurrently triggersrequesttwice per connection (handle it idempotently).wasi/seawill not be implemented.
cargo build # ~25s full debug (mozjs uses a prebuilt static lib)
./target/debug/winterjs2 --eval '40 + 2' # smoke (5 canonical one-liners in AGENTS.md §3)
cargo nextest run --profile strict # full suite (~2 min)
bash scripts/check-lines.sh # every .rs / src JS ≤ 1000 linesWorking conventions: AGENTS.md · progress: docs/plan3.md
(Chinese) · pitfalls: docs/pitfalls.md.
NPL-1.1 (see LICENSE). Vendored third-party JS keeps its MIT headers.



