Skip to content

"Hello WASI!" in Rust via JavaScript using @wasmer/sdk

Open in GitHub Codespaces

We're going to compile some normal-looking Rust code to run in the browser using a WASI runtime. We're going to use the Wasmer SDK which provides a function called runWasix() that lets us run a WebAssembly module in a WASI environment.

Here's our Rust code:

rs
fn main() {
    println!("Hello WASI!");
}

Pretty normal right? Let's compile it to import all the WASI host functions that it needs:

sh
cargo build --target wasm32-wasi
Cargo.toml
toml
[package]
name = "hello-wasi"
version = "0.1.0"
edition = "2021"

🎗️ Make sure that you've installed the wasm32-wasi target for your Rust toolchain! If you're using rustup you can run rustup target add wasm32-wasi to add it.

Now that we have our hello-wasip1.wasm file lets write some JavaScript code to run it with those WASI imports that it needs. We aren't going to implement the WASI API ourselves. Instead, we're going to use the Wasmer SDK which provides a WASI-compatible runtime that we can interact with.

index.html
html
<script type="module" src="index.js"></script>
<p>Check the DevTools console!</p>
js
// 1. Import and initialize the Wasmer SDK.
import { init, runWasix } from "@wasmer/sdk";
await init();

// 2. Load the binary contents of the WebAssembly file.
///   If you were in Node.js you'd use 'fs.readFile()'.
const response = await fetch("target/wasm32-wasi/debug/hello-wasi.wasm");
const buffer = await response.arrayBuffer();

// 3. Compile the WebAssembly blob into a 'WebAssembly.Module'.
//    This will throw an error if the buffer isn't valid WebAssembly.
const module = await WebAssembly.compile(buffer);

// 4. Instantiate the module using the WASI wrapper.
const instance = await runWasix(module, {});

// 5. Wait for the program to run to completion.
const result = await instance.wait();
console.log({
  code: result.code,
  stdout: result.stdout,
  stderr: result.stderr,
});

🎗️ Remember to run npm install @wasmer/sdk to install the npm package locally!

📚 The real magic ✨ here is with the runWasix() function and the instance.wait() promise. You can check out the Wasmer SDK's documentation for more information about the options that you can use to modify the behaviour of the WASI runtime.

Now you can run the code using vite to start a dev HTTP server and see the results:

Note that you'll need to add a vite.config.js or similar file like this in order to add the required headers to enable SharedArrayBuffer which runWasix() uses.

🤩 Imagine what you can do now that you can compile CLI-like apps to WASI!

💡 For a next-level challenge see if you can run the same hello-wasip1.wasm app that we ran in the browser using a Python-based WASI WebAssembly runtime.