Nearoo
Nearoo

Reputation: 4936

How to re-initialize a module generated by wasm-bindgen?

How do I instanciate multiple wasm modules generated using wasm-bindgen?

We're using --target web, which generates a js wrapper code, which exports an "init" function using export default.

The first line of that init function is:

if (wasm !== undefined) return wasm;

If wasm is undefined, it will instanciate the wasm module, then set wasm = wasm.exports, which it appears to return.

If I'd like to start fresh, how would I do that, while keeping the convenient wrapper code?

Upvotes: 1

Views: 142

Answers (1)

Nearoo
Nearoo

Reputation: 4936

One workaround I found is to make js re-evaluate the wrapper module as though it was a new module.

One way to achieve this is to dynamically import the module when the instance is created, in such a way that the URL changes every time a new instance is created. This can be done by turning the wrapper code into a binary blob and calling URL.createObjectURL(blob) multiple times, which will create a new URL every single time.

The following snipped is slightly adjusted to work in vite, depending on setup it will have to be adjusted:


// import type to have typed wasm instance
import type * as wasmBindgen from "./wasm_bindgen_restart_test";

// import the wrapper code as a string, notice `.js` and `?raw`
import wasmWrapperCode from "./wasm_bindgen_restart_test.js?raw";

// take the "type of the module", but leave out the default export
type WasmState = Omit<typeof wasmBindgen, "default">

// create a blob of the js text to which we can find an URL
const wasmWrapperBlob = new Blob([wasmWrapperCode], { type: "application/javascript" });

/** Instanciate a new WASM instance **/
const instanciate = async (): Promise<WasmState> => {
    // dynamicall import the wasm code. URL.createObjectURL will create a fresh
    // URL every time it's called, so the module will be treated as though
    // JS had never seen it before.
    //
    // /* @vite-ignore */ is needed so vite doesn't complain about being unable
    // to determine the import URL at compile time. 
    const wasmWrapper = await import(/* @vite-ignore */  URL.createObjectURL(wasmWrapperBlob));
    
    // now call the default export from the wrapper code, usually called "init"
    await wasmWrapper.default("./wasm/wasm_bindgen_restart_test_bg.wasm");
    return wasmWrapper
}


export { instanciate };

Tested it in a greefield context, but take it with a grain of salt.

Upvotes: 0

Related Questions