
There’s a shift happening in how we think about browser-side processing. For years, JavaScript was the undisputed king of the client-side web. But as web applications demand more — real-time image processing, complex calculations, or heavy data transformations — JavaScript’s single-threaded nature starts to show its limits. Enter WebAssembly (WASM), and when you pair it with Rust, you get a level of performance that feels native.
I’ve been experimenting with WASM modules for a few months now, and the results are consistently impressive. In this tutorial, we’re going to build a high-performance WASM module using Rust. We’ll write a function that performs a task JavaScript struggles with: high-speed data processing. By the end, you’ll have a working WASM module integrated into a simple web page.
Why Rust for WebAssembly?
Rust is a systems programming language known for its safety and speed. It compiles to highly efficient machine code and has first-class support for WebAssembly. Unlike other languages, Rust doesn’t require a garbage collector, which keeps the WASM binary small and execution fast. For tasks where every millisecond counts, this combination is hard to beat.
Prerequisites
- A terminal and a code editor (VS Code works great)
- Rust installed (via
rustup) wasm-packinstalled (we’ll do this in the first step)- A basic understanding of HTML and JavaScript
Step 1: Setting Up the Rust Project
Open your terminal and create a new Rust library project. We’ll call it wasm-perf-demo.
cargo new --lib wasm-perf-demo
cd wasm-perf-demo
Next, install wasm-pack, the tool that builds, tests, and publishes Rust-generated WebAssembly.
cargo install wasm-pack
Step 2: Writing the Rust Logic
Open Cargo.toml and add the wasm-bindgen dependency. This crate provides the bridge between Rust and JavaScript.
[package]
name = "wasm-perf-demo"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "0.2"
Now, replace the contents of src/lib.rs with our performance-heavy function. We’ll write a simple function that calculates a large Fibonacci number. While the logic is simple, it demonstrates the raw execution speed Rust brings to the table.
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn fib(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => {
let mut a: u64 = 0;
let mut b: u64 = 1;
for _ in 2..=n {
let temp = b;
b = a + b;
a = temp;
}
b
}
}
}
Step 3: Building the WASM Module
With our code ready, we use wasm-pack to build it for the web target.
wasm-pack build --target web
This command compiles the Rust code to WASM and generates a pkg directory containing the compiled module and JavaScript bindings.
Step 4: Integrating with JavaScript
Create an index.html file in the root of your project (not inside pkg). This will be our testing ground.
<!DOCTYPE html>
<html>
<head>
<title>WASM Performance Demo</title>
</head>
<body>
<h1>Rust WASM Performance</h1>
<p>Click the button to run the calculation.</p>
<button id="run-btn">Run WASM</button>
<p>Result: <span id="result">...</span></p>
<script type="module">
import init, { fib } from './pkg/wasm_perf_demo.js';
async function run() {
await init();
const n = 45;
const start = performance.now();
const result = fib(n);
const end = performance.now();
document.getElementById('result').innerText = `Fib(${n}) = ${result} (took ${end - start}ms)`;
}
document.getElementById('run-btn').onclick = run;
</script>
</body>
</html>
Step 5: Verifying the Result
To view this, you’ll need to serve the files over HTTP. You can use a simple Python server:
python3 -m http.server 8080
Navigate to http://localhost:8080 in your browser, open the console, and click the button. You’ll see the result appear almost instantly.
Where to Go from Here
This was a simple demo, but the potential is massive. You can use WASM for image processing, cryptographic hashing, or even running entire game engines in the browser. If you’re looking to optimize your web apps, exploring Rust and WASM is a solid next step. It complements modern DevOps practices like automated testing and CI/CD pipelines by ensuring your client-side logic is as robust as your server-side infrastructure. And don’t forget — even if you’re writing high-performance Rust code, testing your code with pytest is still a good habit.