๐ŸŽ“ A1Learner
๐Ÿ”

Rust WebAssembly

WebAssembly is a compact instruction language that browsers run. Rust can compile straight to WebAssembly, so the same Rust code runs inside a page.

A new target for the compiler

A target names the machine your code will run on. This one names the browser's virtual machine:

// in your terminal:
// $ rustup target add wasm32-unknown-unknown

The crate builds as a library

A Wasm crate has no main. It is a library that a page loads. The rlib half keeps normal cargo test working:

// Cargo.toml
[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
wasm-bindgen = "0.2"

Mark what JavaScript may call

The attribute is the export sticker. Only marked items cross to JavaScript:

#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

One command builds the package

wasm-pack compiles for the target. It then runs wasm-bindgen and writes the package:

// in your terminal:
// $ wasm-pack build
// pkg/ now holds the .wasm file, the JS glue,
// and a package.json for the page or npm

The page calls your Rust

The page loads the module first. Then your functions feel like plain JavaScript functions:

import init, { add } from "./pkg/greeter.js";
await init();
console.log(add(2, 3));

Example

// Cargo.toml: [lib] crate-type = ["cdylib", "rlib"]
// Cargo.toml: [dependencies] wasm-bindgen = "0.2"
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Hello, {name}!")
}

Key points

  • WebAssembly: a compact binary format that browsers run next to JavaScript, at close to native speed
  • Rust fits it well: no garbage collector, no runtime, and small output files
  • Use rustup target add to teach your compiler the new target: wasm32-unknown-unknown
  • wasm-pack is the workflow tool.
  • It builds the crate.
  • It generates the JavaScript glue.
  • It packs the result into a pkg folder
  • JavaScript stays in charge of the page: it loads the module and calls your functions
  • A .wasm file cannot touch the page, the files, or the network by itself.

In this example, the crate is the whole greeter. The use line brings in the wasm_bindgen attribute. add takes two whole numbers and returns their sum. greet takes text and builds a greeting String. wasm-pack build turns this file into a package. A JavaScript host then calls add(2, 3) and greet("Ferris"). The console shows the two results: 5 and Hello, Ferris!. Nothing here runs on your machine. The same Rust code runs inside the page.

Note

Every outside power arrives through JavaScript.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Rust Playground

Exercise

What does the target name wasm32-unknown-unknown tell the compiler?