Reputation: 4936
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
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