rustwasm / wasm-pack

📦✨ your favorite rust -> wasm workflow tool!
https://rustwasm.github.io/wasm-pack/
Apache License 2.0
6.2k stars 404 forks source link

Using a no-modules build with ES6 dynamic imports #950

Open tomka opened 3 years ago

tomka commented 3 years ago

To use WASM code in a service worker, I am using wasm-pack 0.9.1 and build my library with wasm-pack build --target no-modules --release, which generates the respective .wasm and .js file. Assuming the path to both files is available in JS as jsPath and wasmPath, I try to do the following to dynamically import the wasm library:

// An IIFE is created in this way to avoid parse errors of the file in some older browser versions.
let promiseWasm = (new Function(`return import('${jsPath}')`))()         
    .then(wasmModule => wasm_bindgen(wasmPath).then(() => wasm_bindgen));

The wasmModule result is not a module but only a Symbol, hence it can't be used directly. But even though the wasm_bindgen variable is defined in the .js file, it is not part of the global namespace (I suppose because it is defined as let). It's understandable that this variable is likely available after static imports like in the no-modules wasm-bindgen example, because it will just be defined prior the other code, but how to make the wasm_bindgen variable available after a dynamic import like the one above?

If I build with the web target, I can use the wasmModule an actual module with all its exports. This however doesn't seem to work with service workers where I then get an error about the export syntax in the generated module. Therefore I assume I need to use no-modules.

Thank you for any ideas! I am not sure this is a bug and it could easily be a misunderstanding on my side.

tomka commented 3 years ago

After more testing it seems that a workaround (or rather a questionable hack) to "export" the wasm_bindgen variable from the imported module into the global namespace is to manually add a line like this to the wasm-pack generated no-modules .js file:

self.my_wasm_bindgen = wasm_bindgen;

When this file is imported as a module, my_wasm_bindgen will be available in the global namespace. It seems that for some reason, self is the global context within the module, when it is imported. I am not sure why that is, but it fixes my problem for now. It just seems rather fragile and requires a manual extra step.