Compiling Rust to WebAssembly should be the best choice for fast, reliable code for the Web. Additionally, the same way that Rust integrates with C calling conventions and libraries on native targets, Rust should also integrate with JavaScript and HTML5 on the Web. These are the Rust and WebAssembly domain working group’s core values.

In 2018, we made it possible to surgically replace performance-sensitive JavaScript with Rust-generated WebAssembly.

I propose that we make larger-scale adoption of Rust and WebAssembly practical in 2019.

#RustWasm2019: To provide some context for this blog post, the Rust and WebAssembly domain working group is currently soliciting proposals for its 2019 roadmap. This is my proposal. I encourage you to add your voice to the discussion as well!

A Rising Tide Lifts All Boats

We should build a toolkit of loosely coupled libraries that make Rust and WebAssembly development practical. Whether you are carefully inserting a small wasm module into an existing JavaScript system, architecting a large wasm module, or starting a green-field Web application, this toolkit should make you productive.

People use high-level libraries and frameworks instead of using Web APIs directly because they want abstractions with which they can naturally express themselves. For example:

  • I prefer describing how I want the DOM to look like right now, rather than enumerating a list of modifications that will transform its current state into my desired state.
  • I prefer thinking in terms of Rust types, not about the raw, serialized bytes in a fetched HTTP response body or about object stores in Indexed DB.

In order to get to rise to that level of abstraction, we will need a diverse set of libraries for the various capabilities the Web exposes:

  • Networking, fetch, and WebSockets
  • Working with forms and <input>
  • Timers and setTimeout
  • Web GL and Web Audio
  • Persistent client storage with Indexed DB
  • A console.log-based backend for env_logger and the Rust logging facade
  • URL routing and window.history
  • Custom elements and Web components
  • Etc…

In 2018, we made using all of these things possible in that you can access the underlying JavaScript and Web APIs directly via wasm-bindgen, js-sys and web-sy, but this is equivalent to programming against the libc crate directly. In 2019, we should create higher-level abstractions that wrap the raw, underlying API to yield a better experience that is ultimately more practical. Green-field Rust and WebAssembly applications would use an umbrella crate that connects the whole toolkit together and re-exports its individual crates. Small, targeted wasm modules that are integrating back into an existing JavaScript application would pick and choose relevant libraries from the toolkit instead of depending upon the whole umbrella crate.

We should collectively build these higher-level libraries and the toolkit’s umbrella crate that connects them together. There is a ton of room here for contributors to step up and provide leadership for a particular component library. This toolkit and all of its crates should reflect our working group’s core values:

  • Fast: Let’s show everyone how fast the Web can be ;-) Zero-cost abstractions from the ground up. No wandering off the happy path to fall off a performance cliff. No frames dropped.

  • Reliable: One of the things that I love about the Rust community is the high standards we hold ourselves to, in particular for correctness. We should leverage Rust’s type system to enforce correctness, write property-based tests with quickcheck, and have comprehensive integration tests running in headless browsers. We intend to build a solid foundation, and there shouldn’t be reason to question its structural integrity.

  • Excellent integration with JavaScript and the Web: We must empower incremental Rust and WebAssembly adoption: rewriting from scratch is not practical. Plus, there is a bunch of JavaScript code that wouldn’t make sense to rewrite in Rust because it is just fine right now.

In addition to supporting our core values, our toolkit should also be:

  • Modular: Take or leave any individual crate from the toolkit. We do not want to build a monolithic, walled garden! The goal is to amplify sharing, compatibility, and improvements; reducing effort duplication across the blossoming Rust and WebAssembly ecosystem.

  • Ergonomic: Rust’s abstractions are not only zero-cost, they are also expressive! We should leverage this to build APIs that are a joy to work with. The glium crate is an excellent example of transmuting a beautiful Rust crate from a crufty API that was not designed for the Rust language.

Some of the aforementioned Web APIs are already wrapped up into high-level APIs in crates that already exist. However, few of the extant crates fulfill all of our requirements. Most commonly they are lacking modularity: we’ve seen more “frameworks” than single-purpose libraries collected into “toolkits”. Nonetheless, we should collaborate to improve existing crates and tease them apart into small, single-purpose libraries where it makes sense and everyone is on board.

Finally, the inspiration for this idea of developing a loosely coupled toolkit comes from the Rust Networking domain working group’s Tide project, and also from the Choo JavaScript project. Thanks!

Tooling

Right now, wasm-pack will orchestrate your building and testing workflows, and generate a package.json file to help you integrate with JavaScript tooling. It will publish your Rust-generated WebAssembly package to NPM, making distribution easy.

But there are a few things that we intended to include in 2018 that didn’t quite make the cut:

  • Integrating and automating execution of the binaryen project’s wasm-opt tool.
  • Support for generating a single NPM package that will work both on the Web and in Node.js.
  • Allowing a library crate X to declare that it has a runtime dependency on an external NPM package, and have that reflected in the package.json that wasm-pack produces for some crate Y that transitively depends on X.
  • Including local assets (notably JavaScript snippets) into wasm-pack’s generated NPM package. Again, with support for crates that are transitively depended upon.

I suspect the latter two items in particular will be necessary for building out the toolkit.

We should finish these tasks and polish wasm-pack into a 1.0 tool. Following that, we should let experience and necessity guide our efforts.

One final note on tooling: Internet Explorer 11 is the last browser that still has non-trivial market share and doesn’t support wasm. It is mostly possible to support IE11 by using the binaryen project’s wasm2js tool to compile our wasm into JavaScript. But wasm2js is still missing some core functionality, and the whole experience of writing a Rust and wasm app while also supporting IE11 is far from turnkey. Because this is so important for actually shipping a Rust and wasm project, we shouldn’t leave this problem for users to solve via integration with external tooling: we should build support for it into our toolchain. This way we can provide that turnkey experience, and make sure that all wasm code that our toolchain emits is fully supported on Internet Explorer 11.

Multithreading

We must bring Rust’s fearless concurrency to the Web!

Of the languages (C, C++, and Rust) that can use shared memory threading on the Web, only Rust can safely do so. The Web APIs necessary for multithreading are stabilizing and will be enabled by default in browsers soon. We should be ready.

However, we can’t just make std::thread work transparently in wasm, due to the nature of the APIs the Web platform is exposing. For example, we can’t block the event loop indefinitely, even in a worker thread, and we need to change the global allocator to avoid waiting on locks on the main thread. See Alex’s excellent Multithreading Rust and WebAssembly write up for details.

Therefore, I think this multithreading effort will mostly involve creating a thread pool library for the whole wasm ecosystem to share, and then building channels and other concurrency abstractions on top of it. We should also get support for wasm threading and our thread pool library upstream into crates like rayon as well. This isn’t actually that different from the library and toolkit work, but it is worth singling out due to its scale, the unique nature of the problem domain, and what a huge game changer multithreading on the Web will be.

#RustWasm2019

I think 2019 holds a very bright future for Rust and WebAssembly.