Skip to Content
Course content

85: Building a Simple WebAssembly Module

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're running a busy restaurant. Your front-of-house manager (JavaScript) is great at multitasking—they handle the customers, take orders, and keep the vibe right. But when it comes to the actual cooking, the manager doesn't touch the stove. Instead, they hand a ticket to a specialist chef (WebAssembly) in the kitchen. The chef doesn't care about the customers or the decor; they just take raw ingredients, perform a highly optimized series of actions, and slide a finished plate back through the window. The manager doesn't need to know how the chef chops the onions; they just need to know how to send the order and receive the food.

In this scenario, JavaScript is your manager. It's flexible and manages the UI, but it can struggle with heavy computation. Rust is our specialist chef. By compiling Rust to WebAssembly (Wasm), we create a binary module that the browser can execute at near-native speed. The "window" where the ticket and plate are exchanged is handled by a tool called wasm-bindgen, which translates Rust's types into something JavaScript can understand.

Setting Up the Specialist's Kitchen

Before we write any code, you'll need wasm-pack. I've used a few different toolchains for Wasm, but wasm-pack is the gold standard because it handles the compilation to .wasm and generates the JavaScript "glue" code automatically. If you haven't installed it yet, go grab it now.

Your Cargo.toml needs two things: the cdylib crate type (which tells Rust to create a dynamic system library for Wasm) and the wasm-bindgen dependency. I usually put wasm-bindgen in the dependencies list like this:

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

Writing High-Performance Logic

Let's build something more substantial than a greeting. We'll create a prime number checker. While JS can do this, a heavy loop checking millions of numbers is exactly where Rust's efficiency shines. I want this function to be accessible from the browser, so we use the #[wasm_bindgen] attribute.

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn is_prime(n: u32) -> bool {
    if n <= 1 { return false; }
    if n <= 3 { return true; }
    if n % 2 == 0 || n % 3 == 0 { return false; }
    
    let mut i = 5;
    while i * i <= n {
        if n % i == 0 || n % (i + 2) == 0 {
            return false;
        }
        i += 6;
    }
    true
}

Notice that I used u32. WebAssembly is very strict about types. When this compiles, wasm-bindgen will make sure that when JavaScript passes a number, it's treated as an unsigned 32-bit integer inside the Rust module.

Bridging the Gap to the Browser

Now, the magic happens during the build process. You don't just run cargo build; you run wasm-pack build --target web. This creates a pkg/ directory containing the compiled .wasm file and a JavaScript wrapper.

I've found that many people get tripped up here: you can't just include a Wasm file in a <script> tag. You have to initialize the module. Here is how you'd actually use our "Chef" in a simple HTML file:

<script type="module">
  import init, { is_prime } from './pkg/prime_checker.js';

  async function run() {
    // This initializes the wasm module
    await init();

    const num = 7919; 
    console.log(`Is ${num} prime? ${is_prime(num)}`);
  }

  run();
</script>

The init() function is crucial. It fetches the .wasm binary and compiles it into the browser's memory. Once that's done, is_prime is just a regular JavaScript function that happens to be executing Rust code under the hood.




📋 Practical Task

Building a Fibonacci Sequence Generator for the Browser

Your task is to expand on the prime checker logic to create a WebAssembly module that calculates Fibonacci numbers. This is a classic example of a recursive or iterative process that benefits from Rust's speed as the input numbers grow.

  • Create a new Rust library project and configure it for cdylib.
  • Implement a function fibonacci(n: u32) -> u32 using the #[wasm_bindgen] attribute.
  • Ensure the function can handle n = 0 and n = 1 correctly.
  • Use wasm-pack build --target web to compile the module.
  • Create a minimal HTML page that imports the generated JS glue code, initializes the module, and logs the 40th Fibonacci number to the console.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.