rustwasm / wasm-bindgen

Facilitating high-level interactions between Wasm modules and JavaScript
https://rustwasm.github.io/docs/wasm-bindgen/
Apache License 2.0
7.71k stars 1.06k forks source link

A flag to not use module-level global variables in web-target #3731

Open alamminsalo opened 10 months ago

alamminsalo commented 10 months ago

Motivation

Lets say a user wants to create an audio plugin system using webassembly which uses a common interface that a plugin must implement in order to load. Currently, when loading multiple plugins using an AudioWorkletProcessor script, 'wasm' variable is set on first call on __wbg_init. This means subsequent loading of next plugin leads to using the already set 'wasm' variable, making it bit challenging to implement such system. Note that AudioWorkletProcessor scripts cannot use dynamic imports, making it hard to get fresh module by for example setting url parameters to bypass cache.

I fixed the problem by wrapping the generated .js file inside a function that returns __wbg_init, initSync and defined Rust types. However, this means I need to redo the modification the module each time it is generated.

Proposed Solution

A flag for web target that allows to load initialize multiple different instances of wasm blobs using the same module. My take was to wrap it inside a function but maybe there is another alternative approach that makes it possible to not break web target api.

Alternative Solutions

In case there is a simple fix that can be implemented using the current codebase, let me know!

daxpedda commented 10 months ago

AFAIK audio worklets support dynamic imports for a while now. Which browser are you experiencing this on?

alamminsalo commented 10 months ago

Chrome and Firefox both throw error of "TypeError: import() is disallowed on WorkletGlobalScope." for the following initialization code (in AudioWorkletProcessor).

const wasm = await import(`../wasm/default?t=${Date.now()}`);
await wasm.default(bytes);

Where ../wasm/default.js is the generated js file with __wbg_init etc.

daxpedda commented 10 months ago

Ah right, I looked it up again, static imports are supported but not dynamic ones.

I think in general we should not be using any global variables in the no-modules target, but I didn't look into how that could be done, but AFAIK it should be possible. We were also discussing before to completely remove the no-modules target in #3355, so that would pose a problem for you.

Generally speaking though, it is considered a bad idea to use wasm-bindgen to produce modules for a plugin system, because the JS bindings can do whatever they want. Usually the solution is to develop a proper plugin API that plugins can use so they are properly sandboxed.

SIGSTACKFAULT commented 9 months ago

just now had a related problem in which the wasm object is re-used if, on a single-page web app, you navigate away from the page with wasm and back. a quick partial solution would be to add a way to destroy the wasm object held in the generated module e.g.,

export function __wbg_reset(){
    wasm = null
}

that way next time you run the __wbg_init you'll get a brand new wasm object

daxpedda commented 9 months ago

Sounds like a B/F cache problem to me.

linonetwo commented 8 months ago

A workaround is in #3818