Rust with WebAssembly

Written — Updated
  • Rust WASM umbrella site:
  • The js_sys crate exposes bindings to a bunch of built-in JS types.
  • Converting Types
    • wasm_bindgen has a JsValue type that represents an arbitrary JS object.The wasm_bindgen docs on interacting with types are also very useful:
    • The wasm_bindgen docs on interacting with types are also very useful:
    • Serde
      • Docs
      • serde can be made to work with JsValue by enabling the serde-serialize feature of wasm-bindgen.
        • wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
      • Then you can use Serialize and Deserialize traits as normal
      • JsValue::from_serde(data) will serialize a Rust type to a JsValue.
      • val::into_serde() will deserialize a value from a JsValue into a Rust type.
      • This does run into issues with things like a Uint8Array inside an object, because it just gets JSON stringified which doesn't work well.
        • The serde-wasm-bindgen crate works around this by doing a direct serialization instead of an intermediary JSON step.
        • serde_wasm_bindgen::to_value(&value) to convert from a Rust type to a JsValue
        • serde_wasm_bindgen::from_value(&js_value) to convert from a JsValue to a Rust type
  • Errors
    • Javascript Errors can be used with the js_sys::Error type.
    • You can wrap any error into a JS Error like this
      • fn wrap_error<T: std::string::ToString>(e: T) -> Error {
            let e = js_sys::Error::new(&e.to_string());
  • wasm-pack
    • This is a tool that works with wasm-bindgen to make it easier to publish WASM blobs.
    • Docs:
    • Use wasm-pack instead of cargo to build your application.
    • Commands
      • wasm-pack new <PROJECT> - Create a new WASM project with Cargo.toml already set up and a skeleton source file.
      • wasm-pack build - Build the library. This will also install the necessary toolchain if you don't have the WASM target installed yet.
  • Examining output size
    • Since WASM is often consumed in the browser, output size can be a concern. The twiggy tool can be used to show what is taking up space.
    • It does need the names section present though, and so adding this to your Cargo.toml will prevent wasm-pack from stripping the names when passing the --profiling option.
      • [package.metadata.wasm-pack.profile.profiling]
        # previously had just ['-O4']
        wasm-opt = ['-O4', '-g']

Thanks for reading! If you have any questions or comments, please send me a note on Twitter.