Skip to content

[build] wasm support#1663

Open
fwbrasil wants to merge 4 commits into
mainfrom
wasm-support
Open

[build] wasm support#1663
fwbrasil wants to merge 4 commits into
mainfrom
wasm-support

Conversation

@fwbrasil
Copy link
Copy Markdown
Collaborator

@fwbrasil fwbrasil commented Jun 5, 2026

Fixes #217

Problem

Kyo cross-compiles to JVM, Scala.js, and Scala Native, but not WebAssembly. Scala.js now ships an experimental WebAssembly backend (WasmGC), so the toolchain exists; Kyo simply had no target wired for it. The goal is WASM as a first-class, tested cross-build target, so the full stack (up to and including kyo-http servers) runs on WasmGC runtimes.

Solution

Add a WasmPlatform to the sbt cross-build, mirroring the existing Scala.js setup (it enables the Scala.js plugin with the experimental WebAssembly linker and ESModule output). The WASM backend shares Scala.js's single-threaded, Node-hosted model, so JS and WASM share platform code through a js-wasm source directory. Most of the diff is mechanical: JS-only sources moving into that shared directory so both backends pick them up.

Every module that targets Scala.js now also targets WASM, except the two cats-effect bridges (see Notes), with a matching CI matrix row and aggregator. The platform-specific code is small: a per-platform trampoline depth in kyo.internal.Platform, a few Node builtin facades for the http tier, and a notWasm tag for the two kernel tests that deliberately overflow the stack. The README gains a Platforms section and a WASM column across the module tables.

Notes

  • Requires Node 24+. Node 24 makes V8's Turboshaft Wasm pipeline the default; Node 22/23 miscompile the generated WasmGC code under legacy TurboFan, and Node 24 removed the opt-in flag. CI, CONTRIBUTING, and the build pin and document this.
  • kyo-cats and kyo-compat-ce are intentionally not built for WASM: cats-effect does not support the backend yet, filed upstream as cats-effect#4608. They re-enable once that lands.
  • This also lowers Scala Native's trampoline depth to match WASM (256, vs 512 on JVM/JS), since native frames are larger and the lower bound is the safe shared value. Flagging it because it changes existing Native behavior.
  • Validated the WASM suite on Node 24 module by module; kyo-http serves real HTTP and HTTPS over Node sockets under WASM. The Chrome/Docker-driven modules (kyo-browser, kyo-ui, kyo-pod) run through the CI matrix.
  • Folds in one pre-existing README fix: kyo-reactive-streams was marked JVM-only but already cross-compiles to JS and Native (corrected, plus WASM).

### Problem

Kyo cross-compiles to JVM, Scala.js, and Scala Native, but not WebAssembly. Scala.js now ships an experimental WebAssembly backend (WasmGC), so the toolchain exists; Kyo simply had no target wired for it. The goal is WASM as a first-class, tested cross-build target, so the full stack (up to and including kyo-http servers) runs on WasmGC runtimes.

### Solution

Add a `WasmPlatform` to the sbt cross-build, mirroring the existing Scala.js setup (it enables the Scala.js plugin with the experimental WebAssembly linker and ESModule output). The WASM backend shares Scala.js's single-threaded, Node-hosted model, so JS and WASM share platform code through a `js-wasm` source directory. Most of the diff is mechanical: JS-only sources moving into that shared directory so both backends pick them up.

Every module that targets Scala.js now also targets WASM, except the two cats-effect bridges (see Notes), with a matching CI matrix row and aggregator. The platform-specific code is small: a per-platform trampoline depth in `kyo.internal.Platform`, a few Node builtin facades for the http tier, and a `notWasm` tag for the two kernel tests that deliberately overflow the stack. The README gains a Platforms section and a WASM column across the module tables.

### Notes

- Requires **Node 24+**. Node 24 makes V8's Turboshaft Wasm pipeline the default; Node 22/23 miscompile the generated WasmGC code under legacy TurboFan, and Node 24 removed the opt-in flag. CI, CONTRIBUTING, and the build pin and document this.
- `kyo-cats` and `kyo-compat-ce` are intentionally not built for WASM: cats-effect does not support the backend yet, filed upstream as [cats-effect#4608](typelevel/cats-effect#4608). They re-enable once that lands.
- This also lowers Scala Native's trampoline depth to match WASM (256, vs 512 on JVM/JS), since native frames are larger and the lower bound is the safe shared value. Flagging it because it changes existing Native behavior.
- Validated the WASM suite on Node 24 module by module; kyo-http serves real HTTP and HTTPS over Node sockets under WASM. The Chrome/Docker-driven modules (kyo-browser, kyo-ui, kyo-pod) run through the CI matrix.
- Folds in one pre-existing README fix: `kyo-reactive-streams` was marked JVM-only but already cross-compiles to JS and Native (corrected, plus WASM).
fwbrasil added 3 commits June 5, 2026 23:38
- build.sbt: keep both imports (WasmCrossProject.* + WithKyoTest._)
- kyo-test: add wasm platform filters (.wasm/.notWasm/.onlyWasm) and a
  Both[A,B] composition marker so .notNative.notWasm gates on both;
  #1658 replaced the ScalaTest tagging #1663 relied on
- KyoTest/ChoiceTest: express the wasm exclusion as .notNative.notWasm
- delete the obsolete ScalaTest Tagged.scala helpers (deleted on main)
#1658 replaced ScalaTest with kyo-test but only cross-built it for
JVM/JS/Native. #1663 runs tests on a 4th target (Wasm), so the kyo-test
modules and the WithKyoTest wiring need a wasm variant.

- build.sbt: add WasmPlatform + .wasmSettings to kyo-test-api/runner/prop/
  snapshot (snapshot keeps WasmPlatform's ESModule for the @jsimport node:fs
  facade); aggregate them into kyoWasm
- WithKyoTest: add a wasm branch wiring kyo-test-runnerWasm and reusing
  JsFramework (wasm is a Scala.js linker backend with the same sbt test bridge)
- move the 15 kyo-test js sources into js-wasm/ (shared js+wasm), mirroring
  how kyo-core shares Scala.js code across js and wasm

Validated: kyoWasm/Test/compile green across all modules; kyo-kernel +
kyo-prelude + kyo-core run green on wasm (2000+ tests, 0 failed) with the
.notNative.notWasm leaves correctly compile-excluded; JS unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wasm Support

1 participant