First steps with WebAssembly in Rust

What is WebAssembly?

JavaScript and WASM engine
  • Encryption
  • Games that require a lot of assets
  • Image and video editing
  • P2P
  • High-performance algorithms
  • VR, AR
  • Visualizations and simulations
  • A big etc…
Photo by XR Expo on Unsplash

Why in Rust?

  • Performance: Rust is free from the non-deterministic garbage collection and it gives to programmers the control over indirection, monomorphization, and memory layout.
  • Small .wasm sizes: Rust lacks a runtime, enabling small .wasm size because there is no extra bloat included like a garbage collector. Hence you only pay in code size, for these functions that you're using.
  • Integration: Rust and Webassembly integrates with existing JavaScript tooling (npm, Webpack…).
Rust performance

Execute Rust code from JavaScript

> cargo install wasm-pack

Rust code

> cargo new helloworld --lib
[package]
name = "helloworld"
version = "0.1.0"
authors = ["Aral Roca Gomez <contact@aralroca.com>"]
edition = "2018"
## new things...
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.67"
[package.metadata.wasm-pack.profile.release]
wasm-opt = ["-Oz", "--enable-mutable-globals"]
  • cdylib lib for wasm final artifacts.
  • wasm-bindgen dependency to facilitate high-level interactions between Wasm modules and JavaScript.
use wasm_bindgen::prelude::*;#[wasm_bindgen]
pub fn helloworld() -> String {
String::from("Hello world from Rust!")
}

Compilation

> wasm-pack build --target web
  • — target bundler — for bundlers like Webpack, Parcel, or Rollup.
  • — target web — for the web as ECMAScript module.
  • — target no-modules — for the web without ECMAScript module.
  • — target nodejs — for Node.js
> ls -l pkg
total 72
-rw-r--r-- 1 aralroca staff 929 Aug 15 13:38 helloworld.d.ts
-rw-r--r-- 1 aralroca staff 3210 Aug 15 13:38 helloworld.js
-rw-r--r-- 1 aralroca staff 313 Aug 15 13:38 helloworld.wasm
-rw-r--r-- 1 aralroca staff 268 Aug 15 13:38 helloworld_bg.d.ts
-rw-r--r-- 1 aralroca staff 15160 Aug 15 13:38 helloworld_bg.wasm
-rw-r--r-- 1 aralroca staff 289 Aug 15 13:38 package.json

Use the compiled code on our JS project

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>"Hello world" in Rust + Webassembly</title>
<script type="module">
import init, { helloworld } from './pkg/helloworld.js'
async function run() {
await init()
document.body.textContent = helloworld()
}
run()
</script>
</head>
<body></body>
</html>

Execute JavaScript code from Rust

use wasm_bindgen::prelude::*;#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[wasm_bindgen]
pub fn example() {
log("Log from rust");
}
import init, { example } from './pkg/helloworld.js'async function run() {
await init()
example() // This will log "Log from rust" to the console
}
run()

Performance — JavaScript vs Rust

use wasm_bindgen::prelude::*;#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
match n {
0 | 1 => n,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
import init, { fibonacci } from './pkg/helloworld.js'function fibonacciInJs(n) {
if (n <= 1) return n
return fibonacciInJs(n - 1) + fibonacciInJs(n - 2)
}
async function run() {
await init()
const num = 20
console.time('Fibonnaci in rust')
const fibRust = fibonacci(num)
console.timeEnd('Fibonnaci in rust')
console.time('Fibonnaci in JS')
const fibJS = fibonacciInJs(num)
console.timeEnd('Fibonnaci in JS')
document.body.textContent = `Fib ${num}: Rust ${fibRust} - JS ${fibJS}`
}
run()
  • In Rust: 0.13ms
  • In JS: 1.28ms

Debugging

> wasm-pack build --target web --debug

Publishing to NPM

>  wasm-pack pack myproject/pkg
> wasm-pack publish

Code from the article

Conclusions

References

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store