How ToT2 Dark_1200x303

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.

  • rustc: This is the compiler for the Rust programming language, provided by the project itself. Compilers take your source code and produce binary code, either as a library or executable.
  • rustup: This installs the Rust programming language from the official release channels, enabling you to easily switch between stable, beta and nightly compilers and keep them updated.
  • cargo: This is the Rust package manager. Cargo downloads your Rust package’s dependencies, compiles your packages, makes distributable packages and uploads them to crates.io, the Rust community’s package registry.
  • deno: This is a JavaScript/TypeScript runtime with secure defaults and a great developer experience.

Set up WebAssembly for Rust

Now, we need to install the following WebAssembly tools for Rust.

     rustup target add wasm32-unknown-unknown
     cargo install wasm-gc
  • wasm32-unknown-unknown: The 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.
  • wasm-gc: A small tool to garbage collect a WebAssembly module and remove all unneeded exports, imports, functions, etc.

Note: If you are using Visual Studio Code for development, install the following extensions.

  • Better Toml bungcip.better-toml
  • Rust rust-lang.rust

Create a Cargo Lib

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.

Create a Rust Function

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.

Compiling the Rust to WebAssembly

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.

Load and Execute Binary with Deno

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

Conclusion

And that’s it! You just wrote Rust code, compiled it to WebAssembly, loaded the WASM file into Deno and used the functions.


Chinedu
About the Author

Chinedu Imoh

Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.

Related Posts

Comments

Comments are disabled in preview mode.