concept · WebAssembly

Prototype Bridge

Compare the old approach — hand-writing a JS wrapper class around raw Wasm exports — with the new custom-descriptor approach where the Wasm module configures its own JS prototype. Both live demos run the same Counter logic; the code you write is different.

Before: JS wrapper class

wasm exports (imagined)

// Wasm exports raw functions // instance.exports: // counter_new(initial) → ptr // counter_get(ptr) → i32 // counter_inc(ptr) // counter_add(ptr, n)

javascript — manual wrapper

class Counter { #ptr; constructor(initial = 0) { this.#ptr = exports.counter_new(initial); } get() { return exports.counter_get(this.#ptr); } inc() { exports.counter_inc(this.#ptr); return this; } add(n) { exports.counter_add(this.#ptr, n); return this; } } // Boilerplate duplicated for every Wasm type
Click a button to interact…
Instance Counter.prototype Object.prototype null
After: Custom Descriptors

wat — custom descriptor type

;; Wasm module declares paired types: (rec (type $counter (descriptor $counter.desc) (struct (field $val (mut i32)))) (type $counter.desc (describes $counter) (struct (field (ref null extern))))) ;; Chrome links the JS prototype automatically

javascript — no wrapper class needed

const { instance } = await WebAssembly.instantiateStreaming( fetch('counter.wasm'), imports, { builtins: ['js-prototypes'] } ); const { Counter } = instance.exports; // Prototype already configured by the module const c = new Counter(10); c.inc().add(5); console.log(c.get()); // 16
Click a button to interact…
WasmGC struct Wasm-configured proto Object.prototype null
What changes: In the old approach every Wasm type needs a hand-written JS class. With custom descriptors the Wasm module calls wasm:js-prototypes/configureAll once at init time; Chrome links the prototype automatically. The descriptor object is allocated once per type, not per instance, so large collections of WasmGC objects consume significantly less memory.

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗