I'm building a Chrome extension and I opted to use some WebAssembly functionality. I'm using wasm-pack to build the source because it provides a --target web
that reduces the complexity of plugging in the Wasm functions. Passing integer values between Rust and JS works seamlessly, but I can't seem to be able to pass a string to Rust and vice versa.
Here is what I am working with:
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
#[wasm_bindgen(js_namespace = console)]
fn log(x: &str);
}
#[wasm_bindgen]
pub extern "C" fn add_two(x: i32) -> i32 {
x + 2
}
#[wasm_bindgen]
pub fn hello(name: &str) {
log("Hello") // <-- passing a '&str' directly works. I can see it in the browser.
log(name) // <-- does not seem to work. There is no output
alert(&format!("Hello {}", name)); // <- Only output im getting is "Hello !"
}
Update: More information on how i'm importing and instantiating wasm
After building with wasm-pack and importing the pkg directory generated into my JS folder. I make the contents of the pkg directory available to the project through the manifest.json file as a web_resource.
Here is how i'm loading the script in my content_script.js
(async function() {
// Get the JS File
const src = await import("/pkg/rusty.js");
// Fetch the wasm file.
const wasm_src = chrome.extension.getURL("/pkg/rusty_bg.wasm");
//src has an exported function 'default' that initializes the WebAssembly module.
let wasm = await src.default(wasm_src);
wasm.hello("stack-overflow");
})();
I also noticed that my generated wasm_bg file has some Rust error output at the bottom .
The issue is in how you're loading the code:
(async function() {
// Get the JS File
const src = await import("/pkg/rusty.js");
// Fetch the wasm file.
const wasm_src = chrome.extension.getURL("/pkg/rusty_bg.wasm");
//src has an exported function 'default' that initializes the WebAssembly module.
let wasm = await src.default(wasm_src);
wasm.hello("stack-overflow");
})();
wasm
returned from .default(...)
is an object with raw WebAssembly exports that can operate only on raw numbers.
In this case what's happening is that wasm.hello
expects two integer numbers - pointer and length of the string in WebAssembly memory - and JavaScript happily converts "stack-overflow"
to 0
and provides another 0
as a default value, which is why you're ending up with an empty string on the Rust side.
What you want instead is the wrapped version of the function that takes care of proper conversions. These live directly on imports of the .js
file:
(async function() {
// Get the JS File
const rusty = await import("/pkg/rusty.js");
// Fetch the wasm file.
const wasm_src = chrome.extension.getURL("/pkg/rusty_bg.wasm");
// rusty has an exported function 'default' that initializes the WebAssembly module.
await rusty.default(wasm_src);
rusty.hello("stack-overflow"); // it works!
})();