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
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
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:
- Working with forms and
- Timers and
- Web GL and Web Audio
- Persistent client storage with Indexed DB
console.log-based backend for
env_loggerand the Rust logging facade
- URL routing and
- Custom elements and Web components
In 2018, we made using all of these things possible in that you can access the
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
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.
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
gliumcrate 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.
wasm-pack will orchestrate your building and testing
workflows, and generate a
package.json file to help you integrate with
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
- Support for generating a single NPM package that will work both on the Web and in Node.js.
- Allowing a library crate
Xto declare that it has a runtime dependency on an external NPM package, and have that reflected in the
wasm-packproduces for some crate
Ythat transitively depends on
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
wasm2js tool to
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.
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.
I think 2019 holds a very bright future for Rust and WebAssembly.