- Install rust
$ brew install rustup
$ rustup-init
- Set default toolchain as
nightly
$ rustup default nightly
- Ass
wasm
target
$ rustup target add wasm32-unknown-unknown
- Install
wasm-gc
tool to remove all unneeded exports, imports, functions, and so on from the generated WebAssembly module.
$ cargo instal wasm-gc
- Instal
https
to runs a web server, serving static files from the current directory
$ cargo instal https
- Create rust app, and open its files with your IDE (I'm using idea)
$ cargo new --lib utils
$ cd utils
$ idea .
7.Define the rust CDI lib type in the cargo.toml
:
[package]
name = "utils"
version = "0.1.0"
authors = ["Hasan Yousef <hasan.ajsf@gmail.com>"]
edition = "2018"
[dependencies]
[lib]
crate-type =["cdylib"]
- Define the
extern
function:
#[no_mangle]
pub extern fn add_one(x: u32) -> u32 {
x + 1
}
The extern
keyword is needed to create an interface, so that this function can be invoked from other languages.
The no-mangle
annotation to tell the Rust compiler not to mangle the name of this function.
- Build the wasm file:
$ cargo build --target wasm32-unknown-unknown --release
- Run the
wasm-gc
to optimize the wasm file:
$ wasm-gc target/wasm32-unknown-unknown/release/utils.wasm -o utils.gc.wasm
- Create the
index.html
file, and call thewasm
module through javascript:
<!DOCTYPE html>
<html>
<head>
<script>
WebAssembly.instantiateStreaming(fetch("utils.gc.wasm"))
.then(wasmModule => {
const result = wasmModeult.instance.exports.add_one(3);
const text = document.createTextNode(result);
document.body.appendChild(text);
});
</script>
<head>
<body></body>
<html>
Using instantiateStreaming instead, we can stream, compile, and instantiate a WebAssembly module in one go.
- Run the static file server:
$ http
- Open your browser at:
localhost:8000
ADVANCE
If you want to interact with JavaScript
function, you need to:
- Define these functions signature in the rust file
- Define a bridge/wrapper in the javascript file between these functions
So, if want to call the javascript alert
and another function, let's say, addOne, then the above main.rs
and index.html
files will be as below:
main.rs:
// To call a JavaScript function
// 1. Define the JS functions signatures
extern {
fn addOne(x: u32);
fn alert(x: u32);
}
// 2. Call the JS function using unsafe block
#[no_mangle]
pub extern fn add_one(x: u32) {
unsafe {
addOne(x);
alert(x);
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<script>
const addOne = (number) => {
const text = document.createTextNode(number + 1);
document.body.appendChild(text);
}
const importObject = {
env: {
addOne: addOne,
alert: alert,
}
};
WebAssembly.instantiateStreaming(fetch("utils.gc.wasm"), importObject)
.then(wasmModule => {
const result = wasmModule.instance.exports.add_one(5);
})
</script>
<head>
<body></body>
<html>
For using bindgen
, kindly see my other post
Top comments (4)
WASM is awesome. I'd recommend using
parcel
as a bundler though, it's much simpler to get started with.It automatically applies bindgen?
Not yet: #647
Thank you for a great introductory post!
I found one minor typo in your index.html code:
should of course be