Rust
Learn how to build WebAssembly applications with Rust and Wasmrun.
Overview
Rust provides excellent WebAssembly support with mature tooling and great performance. Wasmrun makes it easy to develop and run Rust-based WASM applications through the wasmrust plugin.
Prerequisites
Before you start, ensure you have:
- Rust 1.85 or higher (install from rustup.rs)
- wasmrun installed (see Installation)
- wasm32 target installed:
rustup target add wasm32-unknown-unknown
Plugin Installation
Install the Rust plugin for Wasmrun:
wasmrun plugin install wasmrust
Verify installation:
wasmrun plugin info wasmrust
Project Setup
Basic Project Structure
Create a new Rust library project:
cargo new --lib my-wasm-project
cd my-wasm-project
Cargo.toml Configuration
Configure your Cargo.toml for WebAssembly:
[package]
name = "my-wasm-project"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
Key configuration points:
crate-type = ["cdylib"]- Creates a dynamic library suitable for WASMwasm-bindgen- Enables JavaScript interop
For Web Applications
If you're building a web application that needs DOM access:
[dependencies]
wasm-bindgen = "0.2"
[dependencies.web-sys]
version = "0.3"
features = [
"console",
"Document",
"Element",
"Window",
]
Writing Rust for WebAssembly
Basic Example
Here's a simple example (src/lib.rs):
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Hello, {}! Welcome to WebAssembly.", name)
}
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
if n <= 1 {
n
} else {
fibonacci(n - 1) + fibonacci(n - 2)
}
}
Console Logging
Add console.log support for debugging:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
macro_rules! console_log {
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}
#[wasm_bindgen]
pub fn process_data(value: i32) -> i32 {
console_log!("Processing value: {}", value);
let result = value * 2;
console_log!("Result: {}", result);
result
}
Working with Arrays
Process JavaScript arrays in Rust:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn sum_array(numbers: &[i32]) -> i32 {
numbers.iter().sum()
}
#[wasm_bindgen]
pub fn sort_array(mut numbers: Vec<i32>) -> Vec<i32> {
numbers.sort();
numbers
}
Development Workflow
Run Development Server
Start the development server with live reload:
wasmrun run . --watch
This will:
- Detect your Rust project
- Compile to WebAssembly
- Start server at
http://localhost:8420 - Auto-reload on file changes
Specify Port
wasmrun run . --port 3000 --watch
Compilation Only
To just compile without starting a server:
wasmrun compile .
With optimization:
wasmrun compile . --optimization release
wasm-bindgen vs Pure WASM
wasm-bindgen (Browser-Based)
Use when:
- Building web applications
- Need DOM access
- Want JavaScript interop
- Deploying to browsers
Example:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn update_dom() {
// Interact with browser
}
Run with: wasmrun run .
Pure WASM (Native Execution)
Use when:
- Building CLI tools
- Server-side processing
- No browser required
- Maximum portability
Configuration for pure WASM:
[package]
name = "my-cli-tool"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "my-cli"
path = "src/main.rs"
[dependencies]
# No wasm-bindgen needed
Run with: wasmrun exec ./target/wasm32-wasi/release/my-cli.wasm
Complete Examples
Example 1: Simple Functions
See examples/rust-hello for a complete working example with multiple exported functions.
# Clone the repository
git clone https://github.com/anistark/wasmrun.git
cd wasmrun/examples/rust-hello
# Run the example
wasmrun run .
Example 2: Web Application
See examples/web-leptos for a full web application using the Leptos framework.
cd wasmrun/examples/web-leptos
wasmrun run . --watch
Native Execution
For native execution without a browser:
Build for WASI
# Cargo.toml
[package]
name = "native-app"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "app"
path = "src/main.rs"
// src/main.rs
fn main() {
println!("Hello from native WASM!");
}
Compile and Execute
# Compile
cargo build --target wasm32-wasi --release
# Execute natively
wasmrun exec ./target/wasm32-wasi/release/app.wasm
Call Specific Functions
# Call a specific exported function
wasmrun exec ./mylib.wasm --call add 5 3
See examples/native-rust for more native execution examples.
Best Practices
1. Error Handling
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn safe_divide(a: f64, b: f64) -> Result<f64, JsValue> {
if b == 0.0 {
Err(JsValue::from_str("Division by zero"))
} else {
Ok(a / b)
}
}
2. Memory Management
Keep allocations minimal and use references when possible:
#[wasm_bindgen]
pub fn process_string(input: &str) -> String {
// Efficient - borrows input
input.to_uppercase()
}
3. Optimization
For production builds:
# Optimize for size
cargo build --target wasm32-unknown-unknown --release
# Further optimization with wasm-opt (if installed)
wasm-opt -Oz -o optimized.wasm target/wasm32-unknown-unknown/release/my_app.wasm
4. Type Safety
Leverage Rust's type system:
#[wasm_bindgen]
pub struct User {
name: String,
age: u32,
}
#[wasm_bindgen]
impl User {
#[wasm_bindgen(constructor)]
pub fn new(name: String, age: u32) -> User {
User { name, age }
}
#[wasm_bindgen(getter)]
pub fn name(&self) -> String {
self.name.clone()
}
}
Troubleshooting
wasm-bindgen Module Detected
If you see this warning with wasmrun exec:
Warning: wasm-bindgen module detected
Solution: wasm-bindgen modules need a browser environment. Use the dev server instead:
wasmrun run .
Build Failures
Missing target:
rustup target add wasm32-unknown-unknown
Plugin not found:
wasmrun plugin install wasmrust
Performance Issues
- Use
--releasebuilds for production - Profile with
cargo flamegraph - Minimize allocations
- Use
&strinstead ofStringwhen possible
Additional Resources
Next Steps
- Explore WASI Support for system interface capabilities
- Learn about Native Execution in depth
- Check out Live Reload for development workflow
- Review the CLI Reference for all available commands