This tutorial takes you through all you need to know to compile a Rust project to WebAssembly and then run it in Deno.
Why Rust? Web applications struggle to attain and retain reliable performance. JavaScript’s dynamic type system and garbage collection pauses don’t help. Seemingly small code changes can result in drastic performance regressions if you accidentally wander off the JIT’s (Just In Time Compiler) happy path.
Rust gives programmers low-level control and reliable performance. It is free from the non-deterministic garbage collection pauses that plague JavaScript. Programmers have control over indirection, monomorphization and memory layout.
Here’s the content we’ll cover, from installing the necessary tools to compile Rust code and the tools to compile it into the WebAssembly format, to finally loading and using the library in Deno. Before we go any further, the following need to be installed on your machine for working with Rust and Deno.
Now, we need to install the following WebAssembly tools for Rust.
rustup target add wasm32-unknown-unknown
cargo install wasm-gc
wasm32-unknown-unknown
target represents a WebAssembly output that makes zero assumptions about its environment, hence the unknown-unknown
. The target is intended to encapsulate use cases that do not rely on any imported functionality. The binaries generated are entirely self-contained by default when using the standard library.Note: If you are using Visual Studio Code for development, install the following extensions.
bungcip.better-toml
rust-lang.rust
First, we need to open Visual Studio Code in our workspace. Next, we need to create a small cargo lib. Open the terminal and run the following command:
cargo new --lib wasm_deno_example
cd wasm_deno_example
Next, open the Cargo.toml
file and add the dependencies for wasm.
//Cargo.toml
[lib]
crate-type =["cdylib"]
Note: cdylib
makes our project usable with other languages like C or in our case wasm
. It also removes all the specific stuff that is needed for rust.
Paste the following code in the src/lib.rs
file.
#[no_mangle]
pub extern "C" fn age(cy: i32, yob: i32) -> i32{
cy - yob
}
This is a simple function that takes in the current year and your year of birth and returns your age.
Note: We added the extern
keyword so that this function can be imported into our Deno code.
Now, we are ready to compile our rust code to wasm code. Run the following code to build it.
$ cargo build --target wasm32-unknown-unknown
Next using the wasm-gc
, we need to remove all unneeded exports, imports, functions, etc.
wasm-gc target/wasm32-unknown-unknown/debug/wasm_deno_example.wasm
Now, we have a wasm
binary ready to be loaded into Deno and executed.
Create a main.ts
file.
touch main.ts
Add the following code to the file.
//main.ts
const wasmCode = await Deno.readFile("./target/wasm32-unknown-unknown/debug/wasm_deno_example.wasm");
const wasmModule = new WebAssembly.Module(wasmCode);
const wasmInstance = new WebAssembly.Instance(wasmModule);
const {
age,
} = wasmInstance.exports;
const yourAge = age(2020, 1994)
console.log(yourAge);
The above code loads the raw file. Then it makes a wasm module out of our file so that we can work with it. Next, it creates an instance of our module so that we can use the functions after which we imported our wasm
age()
function into our Deno code.
To execute the code run the following.
deno run --allow-read main.ts
$ 26
And that’s it! You just wrote Rust code, compiled it to WebAssembly, loaded the WASM file into Deno and used the functions.
Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.