WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications.
Source: WebAssembly
WebAssembly is also designed to run alongside JavaScript, allowing both to work together. It is being developed in a W3C Community Group (CG) whose members include Mozilla, Microsoft, Google and Apple.
WebAssembly is a portable target for the compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.
It doesn’t allow untrusted code to read or write memory outside of a sandbox. That alone makes it a compelling choice for application plug-ins, function-as-a-service services, smart contracts and more.
Features
- Performance: WebAssembly is designed to maintain the performance characteristics of the web platform. WebAssembly aims to execute at native speed by taking advantage of common hardware capabilities available on a wide range of platforms.
- Compact and Efficient: WebAssembly is designed to be a compact format that is both fast to parse and fast to generate.
- Safe and Secure: WebAssembly is designed to be a safe and secure execution environment for code on the web.
- Open and Debuggable: WebAssembly is designed to be open and debuggable, enabling developers to easily inspect, debug, and optimize their code.
WASI (WebAssembly System Interface)
WebAssembly System Interface (WASI) is a modular system interface for WebAssembly. It is designed to be portable and secure, and to provide a standard interface for WebAssembly programs to interact with their host environments.
WASI is designed to be a portable and secure system interface for WebAssembly. It provides a standard interface for WebAssembly programs to interact with their host environments, including file I/O, networking, and other system-level functionality.
Writing Wasm
Text Format
WebAssembly text format is a human-readable representation of WebAssembly binary format. It is designed to be a more compact and easily readable alternative to the binary format.
(module
(func $add (param i32 i32) (result i32)
get_local 0
get_local 1
i32.add)
(export "add" (func $add)))
Compile the text format to binary format using the wat2wasm tool.
wat2wasm add.wat -o add.wasm
Rust
Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. It supports WebAssembly as a compilation target.
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
Compile the Rust code to WebAssembly using the rustc tool.
rustc --target wasm32-unknown-unknown add.rs
Alternatively, you can use the wasm-pack tool to build and work with Rust-generated WebAssembly.
AssemblyScript
AssemblyScript is a strict and type-safe subset of TypeScript that compiles to WebAssembly. The best part is that you can write AssemblyScript code similar to TypeScript.
export function add(a: i32, b: i32): i32 {
return a + b;
}
Compile the AssemblyScript code to WebAssembly using the asc tool.
asc add.ts -b add.wasm
Go
Go 1.11 added an experimental port to WebAssembly. Go 1.12 has improved some parts of it, with further improvements expected in Go 1.13. Go 1.21 added a new port targeting the WASI syscall API.
package main
import "C"
func add(a, b int) int {
return a + b
}
func main() {}
Compile the Go code to WebAssembly using the go tool.
GOOS=js GOARCH=wasm go build -o add.wasm
Benchmarks
According to the this benchmark, WebAssembly is faster than JavaScript in most cases.
But which is the faster between version of WebAssembly generated from Go, Rust, and AssemblyScript?
| Language | File-size (kb) | Runtime (ms) | Memory (mb) |
|---|---|---|---|
| JavaScript (JS) | 1.3 | 68,720 | 55.7 |
| AssemblyScript (AS) | 4.7 | 6,405 | 21.5 |
| Rust | 74.0 | 2,982 | 21.1 |
| Go | 37.0 | 9,717 | 21.5 |
As you can see, Rust is the fastest, followed by AssemblyScript and Go. In any case, WebAssembly is faster than JavaScript by a large margin.
But the file-size of Rust is the largest, followed by Go and AssemblyScript. JavaScript has the smallest file-size.
Running Wasm
Browser
<!DOCTYPE html>
<html>
<head>
<title>WebAssembly</title>
</head>
<body>
<script>
fetch('add.wasm')
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, {}))
.then(results => {
const { instance } = results;
// Call the exported function from the WebAssembly module
const add = instance.exports.add;
console.log(add(1, 2));
});
</script>
</body>
</html>
To debug WebAssembly in the browser, you can use the native WebAssembly debugging in Chrome DevTools.
Please install it by going to this link: goo.gle/wasm-debugging-extension
You also need to enable the WebAssembly debugging feature in Chrome DevTools by clicking the gear (⚙) icon in the top right corner of DevTools pane, go to the Experiments panel and tick WebAssembly Debugging: Enable DWARF support.
Node.js
Node has excellent support for WebAssembly and WASI. Yet, the latter still isn’t enabled by default, and requires command-line flags (–experimental-wasm-bigint –experimental-wasi-unstable-preview1).
import fs from 'fs';
import { WebAssembly } from 'webassembly';
const buffer = fs.readFileSync('add.wasm');
const module = new WebAssembly.Module(buffer);
const instance = new WebAssembly.Instance(module);
// Call the exported function from the WebAssembly module
const add = instance.exports.add;
console.log(add(1, 2));
Other runtimes
WebAssembly runtimes are standalone tools that can run WebAssembly modules outside of a web browser. Some popular WebAssembly runtimes include:
Wasmer: Wasmer is a standalone runtime for WebAssembly, WASI, and Emscripten by the Wasmer team.
Wasmer has the best overall support compatibility with every programming language at super-speed
Wasmtime: Wasmtime is a standalone runtime for WebAssembly, WASI, and the Component Model by the Bytecode Alliance.
Wasmtime is lightning-fast and compact, with good configurability but fewer languages supported
Wasmedge: WasmEdge is a lightweight, high-performance, and extensible WebAssembly runtime for cloud-native, edge, and decentralized applications. It powers serverless apps, embedded functions, microservices, udf, smart contracts, and IoT devices. WasmEdge is currently a CNCF (Cloud Native Computing Foundation) Sandbox project.
Bun also provides a WebAssembly runtime. Unfortunately, JavaScriptCore currently doesn’t perform as well as V8 for WebAssembly. As of today, if you’re looking for a JavaScript+WebAssembly engine, I would thus recommend V8.
It doesn’t support WASI out of the box,
Conclusion
The future of WebAssembly is bright. It is a powerful technology that can be used to build high-performance web applications and server applications. WebAssembly is designed to be fast, compact, safe, and open. It is supported by all major web browsers and is being actively developed by a number of companies and organizations.
WebAssembly definitely shines at some use cases, including:
- Web Applications: WebAssembly can be used to run high-performance web applications.
- Games
- Video and image editing
- CAD/CAM applications
- Scientific simulations
- Server Applications: WebAssembly can be used to run high-performance server applications.
WebAssembly can be used in a number of ways:
- Entirely in WebAssembly
- Alongside JavaScript
- In a Web Worker, compute-oriented task offload.
It still not sure when WebAssembly will be the default choice for web development, but it is definitely a technology to keep an eye on.
Bonus: Leptos a Rust-based web framework
Leptos makes it easy to build applications in the most-loved programming language, combining the best paradigms of modern web development with the power of Rust.
It comes with a built-in WebAssembly runtime, allowing you to run your Rust code directly in the browser.
use leptos::*;
#[component]
fn HomePage() -> impl IntoView {
// Creates a reactive value to update the button
let (count, set_count) = create_signal(0);
let on_click = move |_| set_count.update(|count| *count += 1);
view! {
<h1>"Welcome to Leptos!"</h1>
<button on:click=on_click>"Click Me: " {count}</button>
}
}
You can find a demo of Leptos here. Clone the repository, go to root directory and run:
cargo leptos watch
Now you can see the example in http://localhost:3000. Open DevTools > Network to see .wasm file loaded.
To install Leptos and Rust, please follow instructions here and here