Rust and WebAssembly in 2019
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
fetch
ed 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
, andWebSocket
s - Working with forms and
<input>
- Timers and
setTimeout
- Web GL and Web Audio
- Persistent client storage with Indexed DB
- A
console.log
-based backend forenv_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’swasm-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 thepackage.json
thatwasm-pack
produces for some crateY
that transitively depends onX
. - 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.