Manual Wasm instantiation with WASI Overrides

When a Wasm component depends on functionality provided by WASI, the jco transpile produces a WebAssembly module that can be loaded from NodeJS or the Browser that includes usages of unresolved imports like wasi:random/random.

note

Normally, WASI imports that need to be sourced from elsewhere would be mapped, using the --map option to jco transpile.

These instructions are for when mapping is insufficient or implementations must be redirected or changed at instantiation time.

A common usage of transpilation is to map the imports to a known package, like @bytecodealliance/preview2-shim:

jco transpile \ component.wasm \ --output dist/transpiled \ --map wasi:cli/*@0.2.0=@bytecodealliance/preview2-shim/cli#*

Sometimes you may want to use your own implementation of WASI interfaces (whether partial or complete), known/resolved only at instantiation time.

Using custom WASI overrides during instantiation

To use custom instantiations, we start with the ability to use the default instantiations:

import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"; async function main() { const wasmESModule = await import("path/to/transpiled/component.js"); const component = wasmESModule.instantiate(null, new WASIShim().getImportObject()); } await main();

This is identical to mapping all imports to those provided by @bytecodealliance/preview2-shim.

Sometimes, when using a transpiled module produced by jco, it's necessary to override some of the WASI imports at instantiation time rather than when transpiling the module to begin with.

import { random } from "@bytecodealliance/preview2-shim"; import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"; async function main() { /// Load the ES module generated by `jco transpile` const wasmESModule = await import("path/to/transpiled/component.js"); // Build a customized WASI shim by mizing custom implementations // and the provided implementation const customShim = new WASIShim({ random: { // For these two interfaces we re-use the default provided shim random: random.random, insecure-seed: random.insecureSeed, // For insecure, we can supply our own custom implementation // (in this case, one that is *VERY* insecure) insecure: { getInsecureRandomBytes: (len) => { return new Uint8Array(len).fill(0); } getInsecureRandomU64: () => 42n, } } }); // Instantiate the Wasm component's ES module const component = wasmESModule.instantiate(null, customShim); } await main();

Using WASIShim, you can generate your own custom implementations of WASI, making use of the published shims where necessary.