Skip to content

Repository files navigation

升级浏览器Update Browser,JXL支持Support Chrome155+、Firefox158+、Safari17+   WinterJS2

winterjs2 ❄️

中文版 · 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()'  # → hi

Note: 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.

Screenshots

REPL — Tab completion with an inline docs pane (like Ruby's irb; .doc <name> prints the full page)

winterjs2 REPL: WinterJS2.image. completion menu with docs pane

Engine versions at your fingertips — WinterJS2.versions.mozjs is the pinned SpiderMonkey (Gecko 153)

winterjs2 REPL: WinterJS2.versions completion showing mozjs 153

Vue 3 + Vite driven by winterjs2 — winterjs2 -r build / winterjs2 -r dev, Vue DevTools live in the browser

vite build and vite dev run through winterjs2, Vue app with DevTools in the browser

WinterJS2.media + utilities — decode FLAC from an MP4, encode AV1, draw a QR code in the terminal (Linux x86_64 build)

winterjs2 --run media.js and tools.js output with a terminal QR code

Quick start

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'            # → 42

5-minute path: English / 中文 · 128 runnable examples in sample/ (one per module, all offline-capable).

Usage

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 (中文).

How winterjs2 works

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.

node: API compatibility (Bun height)

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.

Limitations

  • Cross-engine numbers are not comparable (v8 heap stats, allocUnsafe is zero-filled).
  • structuredClone covers plain data (Date/Map/Set come back as plain objects).
  • node:quic session handshake on loopback times out; node:https currently triggers request twice per connection (handle it idempotently).
  • wasi / sea will not be implemented.

Developing

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 lines

Working conventions: AGENTS.md · progress: docs/plan3.md (Chinese) · pitfalls: docs/pitfalls.md.

License

NPL-1.1 (see LICENSE). Vendored third-party JS keeps its MIT headers.

About

❄️ Node.js-like JS runtime on SpiderMonkey (servo/mozjs), pure Rust — node: compat to Bun height

Topics

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages