Introduction to WebAssembly and Rust
Modern web applications require ever-increasing performance. JavaScript, for all its merits, does not always handle computationally complex tasks — image processing, 3D rendering, cryptography, or simulations. This is where WebAssembly (WASM) comes to the rescue — a binary instruction format that runs in the browser at near-native speed.
The Rust language has become one of the best candidates for writing WASM modules: it is safe, fast, and has no garbage collector. In this article, we will explore how to compile Rust code into WebAssembly, bind it with JavaScript, and create real high-performance web applications.
Setting up the Environment for Rust + WASM
Before writing code, install the necessary tools:
- Rust — install via
rustup(official installer). - wasm-pack — the main tool for building WASM packages.
- wasm-bindgen — a library for binding Rust and JavaScript.
- Node.js and npm — for testing and building the frontend.
# Installing wasm-packcurl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
# Creating a new projectcargo new --lib wasm-examplecd wasm-exampleAfter creating the project, open Cargo.toml and add dependencies:
[lib]crate-type = ["cdylib"]
[dependencies]wasm-bindgen = "0.2"Writing Your First Rust Function for WebAssembly
Let's create a simple function that adds two numbers and returns the result. In src/lib.rs write:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]pub fn add(a: i32, b: i32) -> i32 { a + b}The #[wasm_bindgen] attribute automatically generates a JavaScript wrapper for this function. Now let's build the project:
wasm-pack build --target webAfter building, the pkg folder will contain files: .wasm, .js (wrapper) and .d.ts (TypeScript types).
Integration with HTML and JavaScript
Let's create a simple HTML page for testing:
<!DOCTYPE html><html><head> <script type="module"> import init, { add } from './pkg/wasm_example.js';
async function run() { await init(); console.log('2 + 3 =', add(2, 3)); // 5 } run(); </script></head><body> <h1>Rust + WebAssembly is working!</h1></body></html>Open the file via a local server (e.g., python3 -m http.server) — you will see the result 5 in the browser console.
Working with Strings and Complex Data Types
WebAssembly only operates with numbers. For working with strings, arrays, and objects, wasm-bindgen is used, which automatically converts types.
Example: a function returning a string
use wasm_bindgen::prelude::*;
#[wasm_bindgen]pub fn greet(name: &str) -> String { format!("Hello, {}! You are using Rust + WASM.", name)}In JavaScript:
import init, { greet } from './pkg/wasm_example.js';
await init();console.log(greet("Alex")); // "Hello, Alex! You are using Rust + WASM."Working with Arrays (Vec)
To pass arrays, use Vec<T>. Example — a function that doubles all elements:
#[wasm_bindgen]pub fn double_numbers(arr: Vec<i32>) -> Vec<i32> { arr.iter().map(|x| x * 2).collect()}JavaScript code:
const result = double_numbers([1, 2, 3, 4]);console.log(r