Rust for WebAssembly:
Getting Started with wasm-pack

Last updated: April 13, 2025

1. Introduction: Rust Meets the Web

Rust's performance and safety features make it appealing not just for systems programming but also for computationally intensive tasks on the web. WebAssembly (Wasm) provides a way to run code written in languages like Rust, C++, or C# directly in web browsers at near-native speed, alongside JavaScript.

This guide provides a practical introduction to compiling Rust code to WebAssembly using the standard tooling: wasm-pack and wasm-bindgen. We'll create a simple Rust library, expose a function to JavaScript, compile it to Wasm, and call it from a basic HTML page.

Ensure you have Rust installed. If not, see our Getting Started with Rust guide.

2. What is WebAssembly? (Recap)

As covered in our Introduction to WebAssembly, Wasm is a binary instruction format designed as a portable compilation target for high-level languages. It allows running code at high speed within the browser's secure sandbox. Critically, Wasm is designed to interoperate with JavaScript, enabling developers to use Rust (or other languages) for performance-critical modules within a larger web application.

3. The Rust Wasm Toolchain: wasm-pack and wasm-bindgen

The primary tools for Rust and Wasm development are:

  • wasm-pack: A command-line tool for building, testing, and publishing Rust-generated WebAssembly crates. It orchestrates the build process and produces packages suitable for JavaScript consumption (e.g., npm packages).
  • wasm-bindgen: A Rust library and associated CLI tool that facilitates high-level interaction between Wasm modules and JavaScript. It understands Rust types (like strings, structs) and JavaScript types (like JS objects, DOM manipulation) and generates the necessary glue code for communication.

wasm-pack uses wasm-bindgen under the hood.

4. Project Setup

4.1 Installing wasm-pack

Install wasm-pack using Cargo:

cargo install wasm-pack

Verify the installation:

wasm-pack --version

4.2 Creating a Rust Library Project

We need to create a Rust library (lib) project, not a binary (bin) project, as we intend to call its functions from JavaScript.

cargo new rust_wasm_lib --lib
cd rust_wasm_lib

5. Writing Rust Code for Wasm

5.1 Adding wasm-bindgen Dependency

First, configure Cargo.toml to produce a specific type of library suitable for Wasm and add wasm-bindgen as a dependency:

[package]
name = "rust_wasm_lib"
version = "0.1.0"
edition = "2021"

# Add these lines:
[lib]
crate-type = ["cdylib", "rlib"] # Compile to dynamic system library and Rust library format

[dependencies]
# Add wasm-bindgen dependency
wasm-bindgen = "0.2"
  • crate-type = ["cdylib", "rlib"]: Tells Rust to compile our library into a format suitable for dynamic linking (cdylib, needed for Wasm) and also as a standard Rust library (rlib, useful for testing/integration).
  • wasm-bindgen = "0.2": Adds the necessary library dependency. Check crates.io for the latest version.

You can also add the dependency via the command line:

cargo add wasm-bindgen

5.2 Exposing a Function to JavaScript

Now, let's write a simple function in src/lib.rs and expose it to JavaScript using the #[wasm_bindgen] attribute.

Replace the contents of src/lib.rs with:

use wasm_bindgen::prelude::*;

// This attribute marks the function for wasm-bindgen processing
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Hello from Rust, {}!", name)
}

// Example of another simple function
#[wasm_bindgen]
pub fn add(a: u32, b: u32) -> u32 {
    a + b
}

// You can also expose structs or complex logic,
// but let's keep it simple for getting started.
  • use wasm_bindgen::prelude::*;: Imports necessary items from the library.
  • #[wasm_bindgen]: This attribute tells wasm-bindgen to process the following item (in this case, the greet and add functions) and generate the necessary JavaScript glue code to make them callable from JS.
  • pub fn ...: Functions exposed to Wasm must be public (pub).
  • Note that we're using Rust's &str (string slice) and String types. wasm-bindgen handles the conversion to/from JavaScript strings automatically. Similarly, it handles numeric types like u32.

6. Building the WebAssembly Package

Now, use wasm-pack to build the project. We'll target the browser environment.

wasm-pack build --target web

This command will:

  1. Compile your Rust code to WebAssembly (.wasm).
  2. Run wasm-bindgen to generate the JavaScript glue code needed to load and run the Wasm module.
  3. Create a pkg directory containing the generated .wasm file, the JavaScript glue code (e.g., rust_wasm_lib.js), a TypeScript definition file (.d.ts), and a package.json.

The output in the pkg directory is ready to be used by JavaScript bundlers (like Webpack, Rollup, Vite) or directly in a simple HTML setup.

7. Using the Wasm Module in JavaScript

Let's create a simple HTML file to load and use our Wasm module.

7.1 Simple HTML Setup

  1. Create an index.html file in the root of your rust_wasm_lib project (outside the src and pkg directories).
  2. Create a simple JavaScript file, e.g., index.js, in the same directory.

Add the following to index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rust Wasm Example</title>
</head>
<body>
    <h1>Rust + WebAssembly Test</h1>
    <p>Check the console for output.</p>
    <p id="result"></p>

    <!-- Important: Use type="module" for ES module imports -->
    <script type="module" src="./index.js"></script>
</body>
</html>

7.2 JavaScript Integration

Add the following to index.js:

// Import the generated JS module and the greet function from the pkg directory
// Note: Adjust the path if your HTML/JS are not in the project root.
import init, { greet, add } from './pkg/rust_wasm_lib.js';

async function run() {
    // Initialize the Wasm module. This is required before calling exported functions.
    // init() returns a promise that resolves when the Wasm is loaded.
    await init();

    // Call the exported Rust function
    const message = greet("WebAssembly");
    console.log(message); // Output: Hello from Rust, WebAssembly!

    const sum = add(5, 7);
    console.log(`5 + 7 = ${sum}`); // Output: 5 + 7 = 12

    // Display result in the HTML
    const resultElement = document.getElementById('result');
    if (resultElement) {
        resultElement.textContent = `Rust says: "${message}" and 5 + 7 = ${sum}`;
    }
}

run();

This script imports the default export (the initialization function init) and our named exports (greet, add) from the JavaScript glue file generated by wasm-pack. It calls init() to load the .wasm file and then calls the exported functions.

7.3 Running a Simple Server

WebAssembly modules usually need to be served over HTTP(S) due to browser security policies (fetching .wasm files via file:// often doesn't work reliably).

You can use any simple HTTP server. If you have Python installed:

# Python 3
python -m http.server

Or use a Node.js server like http-server:

npm install -g http-server
http-server .

Open your browser to the address provided by the server (e.g., http://localhost:8000 or http://localhost:8080). Open the browser's developer console, and you should see the output from the Rust functions!

8. Conclusion and Next Steps

You've successfully compiled Rust code to WebAssembly and called it from JavaScript! This demonstrates the basic workflow using wasm-pack and wasm-bindgen.

Rust's potential in the web ecosystem via WebAssembly is significant, allowing developers to leverage its performance and safety for complex client-side computations, game development, data processing, and sharing code between server and client.

Further exploration could involve:

  • Passing more complex data structures (structs, vectors) between Rust and JS.
  • Interacting with JavaScript APIs (like DOM manipulation) from Rust.
  • Integrating Rust Wasm modules into modern frontend frameworks (React, Vue, Angular).
  • Optimizing Wasm bundle size and performance.

9. Additional Resources

Related Articles

External Resources