Rust and WebAssembly can combine in many delightful ways. To consolidate our efforts and have the largest, most-positive impact we can, the Rust and WebAssembly domain working group is focusing on one vision:

Surgically inserting Rust compiled to WebAssembly should be the best choice for speeding up the most performance-sensitive JavaScript code paths. Do not throw away your existing code base, because Rust plays well with others. Regardless of whether you are a Rust or Web developer, your natural workflow shouldn’t change because Rust compiled to wasm integrates seamlessly into your preferred tools.

This blog post will expand on these aspirations and describe where we stand in relation to them right now. In a series of follow up posts, we will talk about the next steps for each major component of the Rust and WebAssembly ecosystem.

Are you interested in helping us make these ideals into reality? Join the Rust and WebAssembly domain working group!

Why Focus on Performance-Sensitive Code?

In the most performance-sensitive contexts, JavaScript hinders rather than helps. Its dynamic type system and non-deterministic garbage collection pauses get in the way. Seemingly small code changes can result in drastic performance regressions if you accidentally wander off the JIT’s happy path.

On the other hand, Rust gives programmers low-level control and reliable performance. It is free from the non-deterministic garbage collection pauses. Programmers have control over indirection, monomorphization, and memory layout.

With Rust, we don’t need to be performance gurus who are intimately familiar with the inner workings of each JavaScript implementation’s JIT. We can have speed without wizardry.

Do Not Rewrite — Integrate

Rust compiled to WebAssembly doesn’t have a runtime. This results in small .wasm binary sizes that are proportional to the amount of Rust code that is being compiled to WebAssembly. Binary size is of huge importance since the .wasm must be downloaded over the network. The proportionality means you only pay (in code size) for what you use. In turn, that means it is feasible for existing JavaScript code bases to incrementally and partially adopt Rust.

Keep the code that already works: we can port only our most performance-sensitive JavaScript functions to Rust and gain immediate benefits.

Keep Your Workflow

If you are a JavaScript hacker and want to use a library that is written in Rust and WebAssembly, you shouldn’t have to change your workflow at all. We can publish .wasm packages to npm, and you can depend on them in package.json just like you normally would any other JavaScript library. They can be imported as ECMAScript modules, CommonJS-style requires, or added as a new object property to the JavaScript global. Bundlers will understand Rust and WebAssembly just as well as they understand JavaScript.

If you are a Rust hacker and want to compile your crate to .wasm and share it on npm, you shouldn’t have to change your workflow either. In fact, you shouldn’t even need to install npm, Node.js, and a whole JavaScript development environment. wasm-pack will compile, optimize, and generate JavaScript bindings for your crate. And then it will publish it to npm for you too!

Current Status

This section provides a snapshot of our current ecosystem, the tools that are available right now, and how this compares to the vision described above.

The Rust and WebAssembly Book

Everything we build is for naught if people can’t learn how to use it themselves. So we are writing The Rust and WebAssembly Book.

Right now, it already has a lot of great content:

  • Getting up and running
  • Designing and implementing a non-trivial example (the Game of Life) that integrates Rust and JavaScript
  • Tips for debugging, time profiling, and code size profiling
  • How to publish to npm with wasm-pack

But it doesn’t have a lot of continuity. It feels like a collection of appendices and random tutorials. We will have a follow up blog post detailing its specific needs, and how to help if you’re interested.

wasm-bindgen

wasm-bindgen facilitates communication between Rust and JavaScript. You can import JavaScript things into Rust, and export Rust things to JavaScript. It allows you to send rich types like strings and structs between wasm and JavaScript, rather than only the simple integers and floats defined by the WebAssembly standard.

Here is “Hello, World!” between Rust and JavaScript with wasm-bindgen. First, we import the alert function into Rust and export the greet function to JavaScript:

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}

Then, we import the wasm as an ECMAScript module in JavaScript, and call the greet function:

import { greet } from "./hello_world";

greet("World!");

wasm-bindgen architecture

How does wasm-bindgen work? Simplifying a bit, it is a procedural macro that takes in Rust source code annotated with #[wasm_bindgen] attributes, constructs an abstract syntax tree (AST), and then it emits two artifacts:

  1. Rust bindings that import JavaScript things and export Rust things.

  2. JavaScript bindings that expose a nice interface to Rust-exported things to other JavaScript code and provide the Rust’s desired imports.

wasm-bindgen’s approach to JavaScript binding allows you to pay only for the imports that you use. Just because you imported the window.alert function, you don’t end up with glue code for window.document.

The big downside is that, right now, you always have to declare imports yourself. There are common imports for JavaScript functions and types and the Web platform APIs that will undoubtedly be repeated by many people many times over. Importing these by-hand is both boring and mechanical. We have a plan for fixing this, but you’ll have to wait for a follow up blog post to learn more.

wasm-pack

wasm-pack seeks to be a one-stop shop for building, optimizing, and publishing Rust-generated WebAssembly that you would like to interoperate with JavaScript, in the browser, or with Node.js. wasm-pack helps you build and publish Rust-generated WebAssembly to the npm registry to be used alongside any other JavaScript package in workflows that you already use, such as a bundler like webpack or a service like greenkeeper.

wasm-pack cartoon

Drawing by Lin Clark in Making WebAssembly better for Rust & for all languages

The intention is that if you are a Rust developer and want to publish a crate compiled to wasm on npm, wasm-pack will

  1. compile the crate to WebAssembly with the wasm32-unknown-unknown target,
  2. run the wasm-bindgen CLI tool on the .wasm to generate its JavaScript interface,
  3. run any other post-build tools such as wasm-snip and wasm-opt,
  4. collate any and all npm dependencies your crate and/or its JavaScript bindings might have,
  5. and publish the resulting package on npm.

All without you, the Rust developer, needing to have a JavaScript toolchain up and running.

Right now, steps 1, 2, and 5 are in place, but you still need to have npm installed locally. There are also some more things planned for wasm-pack, and our story for orchestrating builds, dependencies, and publishing coming down the pipe, but you’ll have to wait for the dedicated follow up blog post.

Wait, There’s More!

Twiggy!

Twiggy!

Coming Soon: The Future

As mentioned throughout this post, we’ll be following up with more blog posts detailing specific goals we have for the Rust 2018 edition and how you can help. In the meantime, don’t hesitate to join the Rust and WebAssembly domain working group and help build the future of Rust and WebAssembly now!