Web Technologies

Understanding WebAssembly and Rust in the Browser

By Mohd Baquir Qureshi
Rust Programming Logo

For decades, JavaScript had a monopoly on the browser. While engines like V8 made JS incredibly fast, it still falls short for CPU-intensive tasks like video encoding, 3D rendering, or complex cryptography. WebAssembly (Wasm) changes this entirely.

What is WebAssembly?

WebAssembly is a binary instruction format. It is not a programming language you write by hand; instead, it's a compilation target for languages like C, C++, and Rust. The browser executes this binary code at near-native speed, directly alongside your JavaScript.

Why Rust?

While you can compile C++ to Wasm, Rust has become the de facto language for WebAssembly development for two main reasons:

  1. No Garbage Collector: Unlike Go or C#, Rust does not require a heavy runtime or garbage collector to be bundled into the Wasm file, keeping payload sizes incredibly small.
  2. Memory Safety: Rust's borrow checker prevents the buffer overflows and segmentation faults that plague C++ applications.
  3. Tooling: The wasm-pack CLI makes compiling Rust to Wasm and generating JavaScript bindings completely painless.

A Basic Example: Calculating Fibonacci

Let's say we need to calculate a massive Fibonacci sequence. Doing this recursively in JavaScript will block the main thread and freeze the browser. Here is how you do it in Rust.

// src/lib.rs
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

You compile this using wasm-pack build --target web. It generates a .wasm file and a JavaScript wrapper.

Calling Wasm from JavaScript

Once compiled, using your high-performance Rust code in your React or Vanilla JS app is trivial.

import init, { fibonacci } from './pkg/my_rust_module.js';

async function run() {
    // Initialize the WebAssembly module
    await init();
    
    console.time("Rust execution");
    const result = fibonacci(45); // Runs at near-native speed
    console.timeEnd("Rust execution");
    
    console.log("Result:", result);
}

run();

When Should You Use WebAssembly?

Do not use WebAssembly to manipulate the DOM. Currently, Wasm cannot access the DOM directly; it must call out to JavaScript to do so, and crossing that boundary is slow.

Do use WebAssembly for:

  • Image/Audio processing (e.g., Figma is largely built with Wasm).
  • Physics engines for browser games.
  • Porting existing legacy C++ desktop applications to the web.
  • Heavy cryptographic operations.

Conclusion

WebAssembly isn't replacing JavaScript; it's complementing it. By offloading heavy computational tasks to Rust-compiled Wasm modules, web developers can now build browser-based applications that rival native desktop software in performance.