JS Interop & Loading
WebAssembly does not run on its own. It always runs inside a host environment, and on the web that host is JavaScript. JS is responsible for fetching the .wasm bytes, compiling them into a WebAssembly.Module, instantiating that module with any required imports, and finally calling the exported functions the module exposes. Wasm, for its part, lives in a tightly sandboxed memory environment — it cannot reach out to the DOM, the network, or any browser API unless JavaScript hands it a function that does so.
The host–module boundary
Section titled “The host–module boundary”The relationship between JS and Wasm is deliberate and explicit. Before any Wasm code runs, JavaScript must supply an imports object — a plain JS object whose keys match the import declarations inside the WAT module. Those imports can be JS functions, WebAssembly.Memory instances, WebAssembly.Global instances, or WebAssembly.Table instances. In return, once the module is instantiated, JS gets back an instance.exports object containing every symbol the module chose to export.
flowchart LR JS["JavaScript (host)"] COMPILE["WebAssembly.instantiate(bytes, imports)"] IMPORTS["imports object (functions, memory, globals)"] MODULE["WebAssembly Module"] EXPORTS["instance.exports (functions, memory, globals)"] JS -->|"fetch .wasm bytes"| COMPILE JS -->|"provides"| IMPORTS IMPORTS --> COMPILE COMPILE --> MODULE MODULE -->|"exposes"| EXPORTS EXPORTS -->|"JS calls exports"| JS
A minimal runnable example
Section titled “A minimal runnable example”The WAT module below exports a single function greet that takes no arguments and returns the integer 42. The JavaScript side compiles the bytes, instantiates the module with an empty imports object {}, and calls instance.exports.greet().
(module (func (export "greet") (result i32) i32.const 42))const bytes = await compileWat(wat);const { instance } = await WebAssembly.instantiate(bytes, {});console.log('greet() =', instance.exports.greet()); // 42