← All decisions

Move JavaScript-target testing from Node to Deno; drop the webgpu npm package

testingwebgpudenonoderenderdevops

Context

render's WebGPU render-pass tests were unreliable under Node with the `webgpu` npm package (a Dawn N-API binding that documents itself as WIP): isolated through extensive testing that shader compilation and pipeline creation alone were stable (8/8), but actual render-pass execution through this codebase's real device-acquisition path was only ~20-25% reliable even run completely standalone via `node script.mjs` (no gleeunit involved) -- crashing the rest with native errors (std::system_error, glibc pthread_mutex assertions, or hangs). Every individual piece of the technique (the shader math, the per-entity draw loop, dynamic imports) was 100% reliable as a hand-written isolated probe; only the combination going through the shared device module was unreliable. The user separately flagged, while observing this investigation, that repeatedly writing disposable JavaScript verification scripts for this wasn't a sustainable pattern, and asked for durable, Gleam-primary test infrastructure instead, plus a fresh look at whether Node was even the right runtime to depend on.

Options considered

Keep Node + webgpu npm package, invest more time debugging it — rejected
Already invested a full investigation session; the package self-documents as WIP, and the failure mode (native crashes in a third-party N-API binding) isn't something fixable from Gleam/WGSL code.
Playwright + headless Chromium — rejected
Researched directly: Chromium's own issue tracker states WebGPU is not working yet in headless mode on Linux. Workarounds require headed mode plus Xvfb (a virtual X server) -- a heavier, more fragile setup than the problem being solved, not a good fit for "long-term extensible".
wgpu-native + a Rust CLI bridge — rejected
The most "pure"/decoupled option, and wgpu ships official headless-capture and image-comparison testing utilities purpose-built for exactly this. Not chosen because it introduces an entirely new language/toolchain (Rust) for this project to maintain long-term, when a same-ecosystem option (Deno, which Gleam already supports as a first-class javascript.runtime) turned out to work. Recorded here as a strong second choice if Deno's WebGPU support is ever pulled back or found lacking.
Mock/abstract the GPU calls, test only CPU-side logic — rejected
Would give up real GPU-execution verification entirely, contradicting this project's established discipline (also used for cs) of testing real GPU execution, not mocks.
Deno (built-in WebGPU, backed by the wgpu Rust crate -- the same engine Firefox and Servo use) — chosen
Native to the runtime (no separate N-API bridge layer at all, unlike the Node npm package) and already a first-class supported target: Gleam's own gleam.toml has a javascript.runtime setting that accepts "deno" directly, so this required no new external language or bridge process, just a runtime switch already within Gleam's own supported surface.

Decision

Set javascript.runtime = "deno" in gleam.toml as the project default; added deno.json with unstable: ["webgpu"]; removed the webgpu npm dependency, package.json, package-lock.json, and node_modules entirely; simplified gpu_ffi.mjs to require navigator.gpu directly (throwing a clear error naming Deno if it's absent) instead of falling back to the npm package; added Deno to asdf for version pinning, matching how Erlang/rebar are already managed; added test/glemy/render_test.gleam (previously nonexistent -- render had zero automated coverage) asserting real rendered pixel bytes.

Verification

The exact production shader pattern (multi-entity loop, uniform buffers, world-to-NDC transform) that was ~20-25% reliable under Node was 8/8 clean as an isolated Deno probe, then 20/20 clean through the full gleeunit suite via Deno (plus a further 15/15 confirmation run and a 10/10 run of the pre-existing io/pe/cs suite alone). Independently confirmed Deno is using its native WebGPU, not silently falling back to an npm package, by temporarily removing node_modules and re-running the suite (still 32/32 passed).

Consequences

Node is no longer a supported way to run this project's JavaScript-target tests or code -- gpu_ffi.mjs now throws a clear, actionable error if navigator.gpu is missing, rather than silently degrading. This project has no npm/node_modules footprint at all as of this decision. The disposable verification scripts written during the original Node investigation (_verify_render.mjs and similar) were deleted rather than kept, since their entire purpose was diagnosing a problem that no longer exists; the investigation itself is preserved here and in project memory instead of in throwaway code.

References