trunk
trunk copied to clipboard
Exported wasm functions are not exposed to js code
When trunk initializes the wasm module and calls into it, it does not expose any exported functions for javascript code to use. This means that javascript cannot easily interact with the wasm code.
For any wasm module, trunk will always generate the following script tag:
<script type="module">import init from '/index-cc05ed39af3d3846.js';init('/index-cc05ed39af3d3846_bg.wasm');</script>
oh, I have the same problem. mark!
Same - I worked around it by injecting my own Js script block that does the imports and calls
I used Trunk.toml property pattern_script in the first case but when I wanted it to be externalised to a file I used the inline asset type of HTML to insert the same Js script block but from file.
It would be really cool if we could specify what functions get imported
Same!! And @arichtman, thanks for the tip. I'll leave a more specific workaround for this problem below, in case it helps anyone.
Workaround 🧪
Trunk.toml, add pattern_script in [build] section like:
# Trunk.toml
[build]
pattern_script = "<script type=\"module\">import init from '{base}{js}';init('{base}{wasm}').then(wasm=>window.wasm=wasm);</script>"
And then, you can call your exported function like [wasm_bindgen] fn my_function_from_rust() by window.wasm.my_function_from_rust() in ES. 🎉
- Reference of
pattern_script:- https://github.com/thedodd/trunk/blob/16ba0353822bed5e84d174cadbe02d4659e5a630/src/config/models.rs#L56
- https://github.com/thedodd/trunk/blob/16ba0353822bed5e84d174cadbe02d4659e5a630/src/config/models.rs#L296
See also: https://github.com/thedodd/trunk/issues/298#issuecomment-1251191523
that's nicer than turning off hashing. It also wasn't clear how one imports js file as a module. Ah maybe a copy tag and a script tag - that would probably work.
With everything being a module but all the modules being done by filename with hashes in it seems really hard for rust to call js and js to call rust. I'm probably missing something like how js modules work ;-)
@gilescope As you say, for practical, we need a example of wrapped by a .js bindings module rather than raw .wasm module. I add a few things to the workaround.💖
Additional workarround ; with export/import all binding version. 🧪🍿
# Trunk.toml ; with export/import all binding version.
# see also the original post: https://github.com/thedodd/trunk/issues/298#issuecomment-1233424749
[build]
pattern_script = "<script type=\"module\">import init, * as with_bindings from '{base}{js}';init('{base}{wasm}').then(wasm=>window.wasm=wasm;window.wasm_with_bindings=with_bindings);</script>"
# note:
# - `wasm` => raw wasm module without .js binding module <- it's for so simple and study cases. 🧪
# - `with_bindings` => wasm module wraped with .js binding module <- it's useful for most cases. 🍿
# - it's okay to use one of which👍
Additional workarround ; only "with bindings" version. 🍿
more simply (only "with bindings"):
[build]
pattern_script = "<script type=\"module\">import init, * as with_bindings from '{base}{js}';init('{base}{wasm}').then(()=>window.wasm_with_bindings=with_bindings);</script>"
# of course, you can set as you like to variable name and mount point. (`wasm_with_bindigs`, `window.wasm_with_bindings` )
See also:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
- https://stackoverflow.com/questions/61986932/how-to-pass-a-string-from-js-to-wasm-generated-through-rust-using-wasm-bindgen-w
To add to usagi workaround, here is my current setup:
Trunk.toml:
[build]
pattern_script = """
<script type=\"module\">
import * as bindings from '{base}{js}';
bindings.default('{base}{wasm}').then(wasm=>{
document.dispatchEvent(new CustomEvent(\"wasmload\", {
detail: {
wasm: wasm,
bindings: bindings
}
}))
});
</script>"""
index.js
document.addEventListener("wasmload", event => {
// event.detail contains bindings and raw wasm
let bindings = event.detail.bindings
new bindings.MyRustStruct()
})
I use the custom event, to pass the bindings and raw wasm to my JS files. Currently I register the wasmload event after document load, so that I can access my document.
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
I'm not currently using Trunk in this way, is anyone else waiting on this functionality?
@thedodd is this planned or are the current workarounds the wanted behavior?
is anyone else waiting on this functionality?
I am :)
While above workarounds solve the problem, I feel like they're a bit too hacky compared to conciseness and beauty of the other parts of trunk :)
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
This issue was closed because it has been stalled for 5 days with no activity.
I added this to trunk-ng: https://github.com/ctron/trunk/commit/0e9981eb94ece781281715a18772aeb2aa09187b … it should be part of the next release.
In a nutshell, this will create an import like this:
<script type="module">
import init, * as bindings from '/index-7eeee8fa37b7636a.js';
window.wasmBindings = bindings;
init('/index-7eeee8fa37b7636a_bg.wasm');
</script>
It will also be possible to change the name and disable it altogether.
this is released as part of trunk-ng 0.17.16