WebAssembly (Wasm)
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints.tools list is empty, and the common mistakes — using Wasm for I/O-bound work, ignoring JS/Wasm bridge overhead, shipping unoptimised binaries — do not produce compiler or linter errors. They only reveal themselves through profiling or performance testing in a browser environment. No standard static analysis tool flags these issues automatically.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix field is empty. Correcting a misuse of Wasm (e.g., restructuring frequent small JS/Wasm bridge calls into batched operations, or integrating wasm-opt/LTO into the build pipeline, or re-evaluating which workloads belong in Wasm vs JS) typically requires changes across build configuration, calling code, and module boundaries — more than a one-liner but not a full architectural rewrite.
Closest to 'persistent productivity tax' (b5). Introducing Wasm into a frontend project creates an ongoing tax: build toolchain complexity (Emscripten, wasm-pack, wasm-opt), JS/Wasm interop patterns, and binary size management affect multiple work streams. It's not confined to a single utility, but it doesn't necessarily define the entire system's shape.
Closest to 'serious trap' (t7). The canonical misconception is explicit: developers commonly assume Wasm replaces JavaScript and can access the DOM directly, when in fact all browser API interaction must go through a JavaScript bridge. This directly contradicts the mental model that 'native-speed binary = direct hardware/API access,' which is how native code works in every other context a developer has likely encountered.
TL;DR
Explanation
WebAssembly is a low-level bytecode format designed as a compilation target for languages like C, C++, Rust, and Go. Browsers execute Wasm at near-native speed via a sandboxed virtual machine alongside the JS engine. Wasm modules can be instantiated from JavaScript, share memory via a linear memory buffer, and call JS functions as imports. On the server side, WASI (WebAssembly System Interface) provides a portable, sandboxed runtime model used in edge computing (Cloudflare Workers, Fastly Compute). PHP can run compiled to Wasm via the php-wasm project, enabling PHP execution in the browser. Key use cases: CPU-intensive computations (image processing, codecs, compression), porting existing native libraries to the web without rewriting, and untrusted code sandboxing. Wasm does not replace JavaScript for DOM manipulation — it cannot access the DOM directly and must call JS for any browser API interaction.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Reaching for Wasm to speed up I/O-bound JS code — Wasm only helps CPU-bound work; network and DOM operations are no faster.
- Ignoring the JS/Wasm bridge cost — frequent small calls between JS and Wasm via imports/exports add significant overhead; batch operations.
- Shipping unoptimised Wasm binaries — without wasm-opt or LTO, compiled output can be significantly larger and slower than necessary.
Avoid When
- Do not use Wasm for DOM manipulation, network requests, or anything that must call browser APIs — JS is faster for those due to bridge overhead.
- Avoid Wasm when the compiled binary size outweighs the performance gain for your use case — a 2 MB Wasm module adds to initial load time.
- Do not reach for Wasm before profiling — most web performance bottlenecks are I/O or rendering, not CPU computation.
When To Use
- Use Wasm for CPU-bound browser tasks: image/video processing, audio codecs, compression, cryptography, simulation.
- Use it to port existing C/C++/Rust libraries to the browser without rewriting them in JavaScript.
- Consider Wasm for sandboxed execution of untrusted code — the Wasm VM provides strong isolation by default.
Code Examples
// Calling Wasm per-pixel — bridge overhead dominates:
const wasmProcess = instance.exports.processPixel;
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = wasmProcess(pixels[i]); // JS→Wasm per pixel
}
// Pass entire buffer to Wasm — one bridge call:
const ptr = instance.exports.alloc(pixels.length);
new Uint8Array(instance.exports.memory.buffer, ptr, pixels.length).set(pixels);
instance.exports.processImage(ptr, pixels.length); // single call
const result = new Uint8Array(instance.exports.memory.buffer, ptr, pixels.length);