|
| 1 | +--- |
| 2 | +title: Our Vision for Rust and WebAssembly |
| 3 | +--- |
| 4 | + |
| 5 | +<meta charset="utf-8" /> |
| 6 | + |
| 7 | +**Surgically inserting Rust compiled to WebAssembly should be the best choice |
| 8 | +for speeding up the most performance-sensitive JavaScript code paths.** Do *not* |
| 9 | +throw away your existing code base, because Rust [plays well with |
| 10 | +others][better-for-all]. Regardless if you are a Rust or Web developer, your |
| 11 | +natural workflow shouldn't change because Rust compiled to wasm integrates |
| 12 | +seamlessly into your preferred tools. |
| 13 | + |
| 14 | +This blog post will expand on these aspirations and describe where we stand in |
| 15 | +relation to them right now. In a series of follow up posts, we will talk about |
| 16 | +the next steps for each major component of the Rust and WebAssembly ecosystem. |
| 17 | + |
| 18 | +<style> |
| 19 | +hr { |
| 20 | + margin-top: 2em; |
| 21 | + margin-bottom: 2em; |
| 22 | +} |
| 23 | +</style> |
| 24 | + |
| 25 | +-------------------------------------------------------------------------------- |
| 26 | + |
| 27 | +> [Are you interested in helping us make these ideals into reality? Join the Rust |
| 28 | +and WebAssembly domain working group!][get-involved] |
| 29 | + |
| 30 | +-------------------------------------------------------------------------------- |
| 31 | + |
| 32 | +## Why Focus on Performance-Sensitive Code? |
| 33 | + |
| 34 | +In the most performance-sensitive contexts, JavaScript hinders rather than |
| 35 | +helps. Its dynamic type system and non-deterministic garbage collection pauses |
| 36 | +get in the way. Seemingly small code changes can result in drastic performance |
| 37 | +regressions if you accidentally wander off the JIT's happy path. |
| 38 | + |
| 39 | +On the other hand, Rust gives programmers low-level control and reliable |
| 40 | +performance. It is free from the non-deterministic garbage collection |
| 41 | +pauses. Programmers have control over indirection, monomorphization, and memory |
| 42 | +layout. |
| 43 | + |
| 44 | +With Rust, we don't need to be a performance gurus who are intimately familiar |
| 45 | +with the inner workings of each JavaScript implementation's JIT. We can have |
| 46 | +[speed without wizardry][]. |
| 47 | + |
| 48 | +## Do <u>Not</u> Rewrite — Integrate |
| 49 | + |
| 50 | +Rust compiled to WebAssembly doesn't have a runtime. This enables both small |
| 51 | +`.wasm` binary sizes and `.wasm` binary sizes that are proportional to the |
| 52 | +amount of Rust code that is being compiled to WebAssembly. Binary size is of |
| 53 | +huge importance since the `.wasm` must be downloaded over the network. The |
| 54 | +proportionality means you only pay (in code size) for what you use, and enables |
| 55 | +incremental and partial adoption of Rust into existing JavaScript code bases. |
| 56 | +Existing code bases don't need to be thrown away: we can port only our most |
| 57 | +performance-sensitive JavaScript functions to Rust to gain immediate benefits. |
| 58 | + |
| 59 | +## Keep Your Workflow |
| 60 | + |
| 61 | +If you are a JavaScript hacker and want to use a library that is written in Rust |
| 62 | +and WebAssembly, you shouldn't have to change your workflow at all. We can |
| 63 | +publish `.wasm` packages to npm, and you can depend on them in `package.json` |
| 64 | +just like you normally would any other JavaScript library. They can be imported |
| 65 | +as ECMAScript modules, CommonJS-style `require`s, or added as a new object |
| 66 | +property to the JavaScript global. [Bundlers will understand Rust and |
| 67 | +WebAssembly][webpack-rust-plugin] just as well as they understand JavaScript. |
| 68 | + |
| 69 | +If you are a Rust hacker and want to compile your crate to `.wasm` and share it |
| 70 | +on npm, you shouldn't have to change your workflow either. In fact, you |
| 71 | +shouldn't even need to install npm, Node.js, and a whole JavaScript development |
| 72 | +environment. `wasm-pack` will compile, optimize, and generate JavaScript |
| 73 | +bindings for your crate. And then it will upload it to npm for you too! |
| 74 | + |
| 75 | +## Current Status |
| 76 | + |
| 77 | +This section provides a snapshot of our current ecosystem, the tools that are |
| 78 | +available right now, and how this compares to the vision described above. |
| 79 | + |
| 80 | +### The Rust and WebAssembly Book |
| 81 | + |
| 82 | +Everything we build is for naught if people can't learn how to use it |
| 83 | +themselves. So we are writing [The Rust and WebAssembly Book][book]. |
| 84 | + |
| 85 | +Right now, it already has a lot of great content: |
| 86 | + |
| 87 | +* Getting up and running |
| 88 | +* Designing and implementing a non-trivial example (the Game of Life) that |
| 89 | + integrates Rust and JavaScript |
| 90 | +* Tips for debugging, time profiling, and code size profiling |
| 91 | +* How to publish to npm with `wasm-pack` |
| 92 | + |
| 93 | +But it doesn't have a lot of continuity. It feels like a collection of |
| 94 | +appendices and random tutorials. We will have a follow up blog post detailing |
| 95 | +its specific needs, and how to help if you're interested. |
| 96 | + |
| 97 | +### wasm-bindgen |
| 98 | + |
| 99 | +[`wasm-bindgen` facilitates communication between Rust and |
| 100 | +JavaScript.][wasm-bindgen] You can import JavaScript things into Rust, and |
| 101 | +export Rust things to JavaScript. It allows you to send rich types like strings |
| 102 | +and structs between wasm and JavaScript, rather than only the simple integers |
| 103 | +and floats defined by the WebAssembly standard. |
| 104 | + |
| 105 | +Here is "Hello, World!" between Rust and JavaScript with `wasm-bindgen`. First, |
| 106 | +we import the `alert` function into Rust and export the `greet` function to |
| 107 | +JavaScript: |
| 108 | + |
| 109 | +```rust |
| 110 | +extern crate wasm_bindgen; |
| 111 | +use wasm_bindgen::prelude::*; |
| 112 | + |
| 113 | +#[wasm_bindgen] |
| 114 | +extern { |
| 115 | + fn alert(s: &str); |
| 116 | +} |
| 117 | + |
| 118 | +#[wasm_bindgen] |
| 119 | +pub fn greet(name: &str) { |
| 120 | + alert(&format!("Hello, {}!", name)); |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +Then, we import the wasm as an ECMAScript module in JavaScript, and call the |
| 125 | +`greet` function: |
| 126 | + |
| 127 | +```js |
| 128 | +import { greet } from "./hello_world"; |
| 129 | + |
| 130 | +greet("World!"); |
| 131 | +``` |
| 132 | + |
| 133 | +<a href="/images/wasm-bindgen-architecture-current.png"> |
| 134 | + <img src="/images/wasm-bindgen-architecture-current.png" alt="wasm-bindgen architecture" style="float:right;width:50%;min-width:200px;max-width:400px;margin:1em"/> |
| 135 | +</a> |
| 136 | + |
| 137 | +How does `wasm-bindgen` work? Simplifying a bit, it is a procedural macro that |
| 138 | +takes in Rust source code annotated with `#[wasm_bindgen]` attributes, |
| 139 | +constructs an abstract syntax tree (AST), and then it emits two artifacts: |
| 140 | + |
| 141 | +1. Rust bindings that import JavaScript things and export Rust things. |
| 142 | + |
| 143 | +2. JavaScript bindings that expose a nice interface to Rust-exported things to |
| 144 | + other JavaScript code and provide the Rust's desired imports. |
| 145 | + |
| 146 | +`wasm-bindgen`'s approach to JavaScript binding allows you to pay only for the |
| 147 | +imports that you use. Just because you imported the `window.alert` function, you |
| 148 | +don't end up with glue code for `window.document`. |
| 149 | + |
| 150 | +The big downside is that, right now, you always have to declare imports |
| 151 | +yourself. There are common imports for JavaScript functions and types and the |
| 152 | +Web platform APIs that will undoubtedly be repeated by many people many times |
| 153 | +over. Importing these by-hand is both boring and mechanical. We have a plan for |
| 154 | +fixing this, but you'll have to wait for a follow up blog post to learn more. |
| 155 | + |
| 156 | +<div style="clear: both"/> |
| 157 | + |
| 158 | +### wasm-pack |
| 159 | + |
| 160 | +[`wasm-pack` seeks to be a one-stop shop for building, optimizing, and |
| 161 | +publishing Rust-generated WebAssembly that you would like to interoperate with |
| 162 | +JavaScript, in the browser, or with Node.js.][wasm-pack] `wasm-pack` helps you |
| 163 | +build and publish Rust-generated WebAssembly to the npm registry to be used |
| 164 | +alongside any other JavaScript package in workflows that you already use, such |
| 165 | +as a bundler like [webpack][] or [greenkeeper][]. |
| 166 | + |
| 167 | +[](/images/wasm-pack-cartoon.png) |
| 168 | + |
| 169 | +*Drawing by Lin Clark in [Making WebAssembly better for Rust & for all |
| 170 | +languages][better-for-all]* |
| 171 | + |
| 172 | +The intention is that if you are a Rust developer and want to publish a crate |
| 173 | +compiled to wasm on npm, `wasm-pack` will |
| 174 | + |
| 175 | +1. compile the crate to WebAssembly with the `wasm32-unknown-unknown` target, |
| 176 | +2. run the `wasm-bindgen` CLI tool on the `.wasm` to generate its JavaScript |
| 177 | + interface, |
| 178 | +3. run any other post-build tools such as `wasm-snip` and `wasm-opt`, |
| 179 | +4. collate any and all npm dependencies your crate and/or its JavaScript |
| 180 | + bindings might have, |
| 181 | +5. and publish the resulting package on npm. |
| 182 | + |
| 183 | +All without you, the Rust developer, needing to have a JavaScript toolchain up |
| 184 | +and running. |
| 185 | + |
| 186 | +Right now, steps 1, 2, and 5 are in place, but you still need to have `npm` |
| 187 | +installed locally. There are also some more things planned for `wasm-pack`, and |
| 188 | +our story for orchestrating builds, dependencies, and publishing coming down the |
| 189 | +pipe, but you'll have to wait for the dedicated follow up blog post. |
| 190 | + |
| 191 | +### Wait, There's More! |
| 192 | + |
| 193 | +<a href="/images/twiggy.png"> |
| 194 | + <img src="/images/twiggy.png" alt="Twiggy!" style="float:right;width:40%;min-width:100px;max-width:500px;margin:1em"/> |
| 195 | +</a> |
| 196 | + |
| 197 | +* [Twiggy is a code size profiler for `.wasm` binaries.][twiggy] It helps you |
| 198 | + answer questions like "why did this function even end up in here -- who calls |
| 199 | + it?" and "how much space would be saved if I stopped using this function, |
| 200 | + removed it, and removed all the functions that become dead code after its |
| 201 | + removal?" |
| 202 | + |
| 203 | +* [`wee_alloc` is a tiny allocator designed for WebAssembly that has a (pre |
| 204 | + compression) code size footprint of only a single kilobyte.][wee_alloc] It is |
| 205 | + geared towards code that makes a handful of initial dynamically sized |
| 206 | + allocations, and then performs its heavy lifting without any further |
| 207 | + allocations. This scenario requires *some* allocator to exist, but we are more |
| 208 | + than happy to trade allocation performance for small code size. |
| 209 | + |
| 210 | +<div style="clear: both"/> |
| 211 | + |
| 212 | +<a href="/images/console_error_panic_hook.png"> |
| 213 | + <img src="/images/console_error_panic_hook.png" alt="Twiggy!" style="float:left;width:60%;min-width:100px;max-width:800px;margin:1em"/> |
| 214 | +</a> |
| 215 | + |
| 216 | +* [The `console_error_panic_hook` crate provides a panic hook for wasm that logs |
| 217 | + panics to the developer console via the `console.error` |
| 218 | + function.][console_error_panic_hook] No more opaque "RuntimeError: unreachable |
| 219 | + executed" messages! Get the proper assertion failure message or index |
| 220 | + out-of-bounds information you expect. It makes debugging panics a whole lot |
| 221 | + easier. |
| 222 | + |
| 223 | +* [The `wasm-snip` tool lets you forcibly replace a function's body with a |
| 224 | + single `unreachable` instruction.][wasm-snip] Maybe you know that some |
| 225 | + function will never be called at runtime, but the compiler can't prove that at |
| 226 | + compile time? Snip it! Then run wasm-gc again and all the functions it |
| 227 | + transitively called (which could also never be called at runtime) will get |
| 228 | + removed too. This is particularly helpful for removing Rust's panicking and |
| 229 | + formatting infrastructure when you intend to ship small `.wasm` binaries with |
| 230 | + `panic=abort`. |
| 231 | + |
| 232 | +<div style="clear: both"/> |
| 233 | + |
| 234 | +## Coming Soon: The Future |
| 235 | + |
| 236 | +As mentioned throughout this post, we'll be following up with more blog posts |
| 237 | +detailing specific goals we have for the Rust 2018 edition and how you can |
| 238 | +help. In the meantime, don't hesitate to [join the Rust and WebAssembly domain |
| 239 | +working group and help build the future of Rust and WebAssembly now!][get-involved] |
| 240 | + |
| 241 | + |
| 242 | +[better-for-all]: https://hacks.mozilla.org/2018/03/making-webassembly-better-for-rust-for-all-languages/ |
| 243 | +[get-involved]: https://github.com/rustwasm/team#get-involved |
| 244 | +[speed without wizardry]: http://fitzgeraldnick.com/2018/02/26/speed-without-wizardry.html |
| 245 | +[webpack-rust-plugin]: https://github.com/xtuc/rust-plugin |
| 246 | +[book]: https://rustwasm.github.io/book/ |
| 247 | +[host-bindings]: https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md |
| 248 | +[wasm-bindgen]: https://github.com/rustwasm/wasm-bindgen |
| 249 | +[wasm-pack]: https://github.com/rustwasm/wasm-pack |
| 250 | +[wasm-snip]: https://github.com/rustwasm/wasm-snip |
| 251 | +[console_error_panic_hook]: https://github.com/rustwasm/console_error_panic_hook |
| 252 | +[twiggy]: https://github.com/rustwasm/twiggy |
| 253 | +[wee_alloc]: https://github.com/rustwasm/wee_alloc |
| 254 | +[webpack]: https://webpack.js.org/ |
| 255 | +[greenkeeper]: https://greenkeeper.io/ |
0 commit comments