Published on Oct 8, 2024
WebAssembly (WASM) defines a portable binary code format and corresponding text format for executable programs and interfaces to facilitate communication between the host environment and the application. WASM is designed to be fast, safe, portable and efficient. WASM being portable allows it to be hardware-independent, language-independent and platform-independent. It seems counterintuitive that WASM is being used in places outside the web. It was initially designed for execution within web browsers, but its capabilities have extended far beyond its original purpose. It allows languages other than JavaScript to run efficiently in a web environment. Today, we explore its potential in server-side applications, unlocking new possibilities for performance, portability, and security. Let's start by understanding the fundamentals before going into an example and use cases.
Wasm application development involves a dedicated ecosystem of languages, compilers, frameworks, libraries, tools, and runtimes. Programming languages for Wasm vary across four categories:
From https://www.researchgate.net/figure/WebAssembly-data-flow-architecture_fig1_373229823
WebAssembly supports ahead-of-time (AOT), just-in-time (JIT) compilation, and interpreters, utilized in web browsers and non-browser environments like Wasmer, Wasmtime, and others. Over 40 programming languages can compile to WebAssembly, either directly or through virtual machines implemented in WebAssembly.
From https://www.monarch-innovation.com/aot-vs-jit-compiler-in-angular
Emscripten uses Binaryen and LLVM to compile C, C++, and other LLVM-supported languages to WebAssembly, integrating with JavaScript's environment interfaces like WebGL. Clang can now compile C, C++, Rust, .NET languages, and AssemblyScript to WebAssembly. WebAssembly's post-MVP features include multithreading and garbage collection, enabling support for languages like C#, F#, Python, and even optimizing JavaScript.
Additional languages with varying levels of WebAssembly support include Python, Julia, Ruby, and systems like CheerpJ, JWebAssembly, TeaVM for Java bytecode, and direct support from Kotlin.
A WASM runtime is a software component that executes Wasm bytecode. Runtimes can be standalone or embedded within a host environment, like a web browser or server. Standalone runtimes include WasmEdge, Wasmtime, Wasmer, and others, while embedded runtimes include V8, SpiderMonkey and others. Runtimes provide a sandboxed execution environment for WASM applications, ensuring safety, security and portability.
Runtime Segmentation
Wasm runtimes, akin to operating systems, support high-level libraries and frameworks crucial for application development.
WasmEdge stands out by extending POSIX APIs beyond the standard, enabling popular Rust and JS frameworks like tokio, hyper, and node.js, along with various database clients, to operate within it. Unlike other runtimes, which require frameworks for essential features like networking and database access, WasmEdge is designed as a lightweight, high-performance runtime for cloud-native, edge, and decentralized applications. It supports serverless functions, microservices, smart contracts, and IoT devices, and is recognized as a CNCF Sandbox project.
WasmEdge ensures the secure execution of WebAssembly bytecode within a defined sandbox, safeguarding resources and memory. Its primary use case includes safely running user-contributed code as plug-ins in diverse software environments, fostering extensibility and customization by third-party developers and community members.
While WebAssembly's initial focus was on client-side web applications, its benefits have sparked interest in using it on server-side environments:
The adoption of WebAssembly on servers is evident in various use cases:
Burn is a new comprehensive dynamic Deep Learning Framework built using Rust with extreme flexibility, compute efficiency and portability as its primary goals. With Burn and Rust we can compile training or inference processes to Machine Learning models to WASM and run them anywhere there is a WASM runtime. This is an example of a simple WebAssembly program written in Rust that adds two matrices and returns the result. The code can be found here. This is an example by burn to show how to execute an image classification task in a web browser using a model converted to Rust code.
Before you begin, ensure that you have Rust installed. If not, visit the official Rust website and follow the installation guide.
For WASM development, we'll need the wasm32-wasip1 target, which
can be added with:
rustup target add wasm32-wasip1
Clone this repository:
git clone https://gitea.rodneyosodo.com/rodneyosodo/rust-wasi-example.git
Change to the project directory:
cd rust-wasi-example
The code is in the src/main.rs file.
use burn::{
tensor::{backend::Backend, Tensor},
};
use futures::executor;
pub async fn addition<B: Backend>(
a: [[f32; 2]; 2],
b: [[f32; 2]; 2],
) -> String {
let device = Default::default();
let tensor1: Tensor<B, 2> = Tensor::from_floats(a, &device);
let tensor2: Tensor<B, 2> = Tensor::from_floats(b, &device);
let result = tensor1 + tensor2;
#[cfg(not(target_family = "wasm"))]
return result.to_data().to_string();
#[cfg(target_family = "wasm")]
return result.to_data().await.to_string();
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let a: [[f32; 2]; 2] = serde_json::from_str(&args[1])
.expect("Please provide a valid JSON input for example: [[1.0, 2.0], [3.0, 4.0]]");
let b: [[f32; 2]; 2] = serde_json::from_str(&args[2])
.expect("Please provide a valid JSON input for example: [[1.0, 2.0], [3.0, 4.0]]");
let result = executor::block_on(addition::<burn::backend::NdArray>(a, b));
println!("{:}", result);
}
We have a simple function that takes two matrices and returns the sum of the two matrices. The function is asynchronous and returns a string.
Build the project:
cargo build --target=wasm32-wasip1 --release
This will compile the project into WebAssembly. The compiled file can be found
in the target/wasm32-wasip1/release directory.
To run the project, you would need to install the wasmtime runtime.
You can find the installation instructions
here.
wasmer is another runtime that can be used to run the compiled
WebAssembly file. You can find the installation instructions
here.
To run the compiled WebAssembly file with wasmtime, you can use the
following command:
wasmtime target/wasm32-wasip1/release/rust-wasi-example.wasm '[[1.0, 2.0], [3.0, 4.0]]' '[[1.0, 2.0], [3.0, 4.0]]'
Or with wasmer:
wasmer target/wasm32-wasip1/release/rust-wasi-example.wasm '[[1.0, 2.0], [3.0, 4.0]]' '[[1.0, 2.0], [3.0, 4.0]]'
This will output the result of the addition of the two matrices.
Autodesk leveraged WebAssembly to bring a subset of AutoCAD's features to web browsers. This strategic move democratized access to CAD functionalities, allowing engineers and architects to view and edit drawings directly within their web browsers.
https://www.autodesk.com/blogs/autocad/autocad-web-app-google-io-2018
Figma introduced WebAssembly to optimize critical components of its 2D WebGL rendering engine. This approach allowed complex vector graphics and UI elements to render swiftly, even on less powerful devices. Figma's load times improved by more than 3x across all document sizes after implementing WebAssembly. Moreover, Wasm's efficient parsing and execution model facilitated smoother interactions during collaborative editing sessions, where multiple users simultaneously manipulate designs in real-time.
Zed editor making extensible via WASM
If you liked this article, click theπ below so other people will see it here on Medium.
Let's be friends on Twitter. Happy Coding π
Subscribe to get future posts via email