Universal WebAssembly tools for JavaScript.
unwasm lets you import a .wasm file the same way you import any other module. It reads the module at build time, works out what it imports and exports, and generates the right bindings for your bundler.
import { sum } from "sum.wasm";unwasm aims to be a common, future-proof way to support WebAssembly modules across JavaScript runtimes, frameworks, and build tools. It follows the WebAssembly Community Group's ES Module Integration proposal as closely as possible, while staying compatible with today's ecosystem libraries.
When you import a .wasm module, unwasm resolves, reads, and parses it during the build to discover its imports and exports. It also tries to resolve imports automatically and emits bindings tailored to your bundler.
The shape of those bindings depends on your target environment:
- Static bindings โ if the environment supports top-level
awaitand the module needs no imports object (or unwasm can resolve one for you), the.wasmfile behaves like a regular ESM import. - Lazy bindings โ if top-level
awaitis unavailable, the module needs an imports object, or you set thelazyplugin option, unwasm exports a Proxy that you call as a function to instantiate the module with your own imports. The syntax stays close to ESM, and initialization happens only when you need it.
Example: Using static import
import { sum } from "sum.wasm";Example: Using dynamic import
const { sum } = await import("sum.wasm");If your module requires an imports object (which unwasm can often infer for you), the syntax changes slightly: you initialize the module with that object first.
Example: Using dynamic import with imports object
const { rand } = await import("rand.wasm").then((r) =>
r.default({
env: {
seed: () => () => Math.random() * Date.now(),
},
}),
);Example: Using static import with imports object
import initRand, { rand } from "rand.wasm";
await initRand({
env: {
seed: () => () => Math.random() * Date.now(),
},
});Note
With static import syntax, named exports are proxied until the module is initialized. If you call one of them before init, the proxy runs init without imports and returns a Promise that resolves with the call's result.
Some libraries want a WebAssembly.Module so they can create the WebAssembly.Instance themselves. For those cases, add the ?module suffix to import a .wasm file as a Module directly.
import _sumMod from "sum.wasm?module";
const { sum } = await WebAssembly.instantiate(_sumMod).then((i) => i.exports);Note
Run into a library that needs this? Open an issue โ we would love to help it migrate!
unwasm transforms .wasm imports into compatible bindings at build time. Today that happens through a Rollup plugin; more integrations are planned.
Install the unwasm npm package:
# โจ Auto-detect package manager
npx nypm install unwasm// rollup.config.js
import { unwasm } from "unwasm/plugin";
export default {
plugins: [unwasm({/* options */})],
};esmImport(default:false): Import the.wasmfile directly instead of bundling it. Required on Cloudflare Workers, and works in any environment with native.wasmmodule imports.lazy(default:false): Import.wasmfiles through a lazily evaluated proxy, for runtimes without top-levelawait.
unwasm ships build-time helpers for working with .wasm modules directly.
Parses the wasm binary format to extract a module's imports and exports. It is a small, dependency-free reader that decodes only the sections describing the module interface and skips the rest.
import { readFile } from "node:fs/promises";
import { parseWasm } from "unwasm/tools";
const source = await readFile(new URL("examples/sum.wasm", import.meta.url));
const parsed = parseWasm(source);
console.log(JSON.stringify(parsed, undefined, 2));Example parsed result:
{
"modules": [
{
"exports": [
{
"id": 5,
"name": "rand",
"type": "Func"
},
{
"id": 0,
"name": "memory",
"type": "Memory"
}
],
"imports": [
{
"module": "env",
"name": "seed",
"params": [],
"returnType": "f64"
}
]
}
]
}unwasm can infer the imports object for you and bundle it using import maps (read more: MDN, Node.js, and WICG).
To tell the bundler how to resolve the imports a .wasm file needs, declare them in a parent package.json:
{
"exports": {
"./rand.wasm": "./rand.wasm"
},
"imports": {
"env": "./env.mjs"
}
}Tip
You can prefix import names with # (for example #env) to follow Node.js conventions.
Wasm modules can also import from ES modules (read more: ESM Integration Spec).
Example:
(module
(import "./add-esmi-deps.mjs" "getValue" (func $getValue (result i32)))
(func (export "addImported") (param $a i32) (result i32)
local.get $a
call $getValue
i32.add
)
)Local development
Published under the MIT license.
Made by @pi0 and community ๐
๐ค auto updated with automd