8.1 KiB
obj | mime | extension | website | rev |
---|---|---|---|---|
concept | application/wasm | wasm | https://webassembly.org | 2024-03-26 |
WebAssembly
WebAssembly, often abbreviated as Wasm, is an open standard and binary instruction format designed for a stack-based virtual machine. It aims to execute code efficiently across various platforms, including web browsers. WebAssembly is a portable binary instruction format that serves as a compilation target for high-level programming languages like C, C++, and Rust. It enables these languages to be executed in web browsers at near-native speeds, bridging the performance gap between web applications and native applications.
Features of WebAssembly
1. Efficiency
- WebAssembly binaries are designed to be compact and fast to load, enabling efficient transmission over the network.
- It leverages Just-In-Time (JIT) compilation techniques for optimal runtime performance.
2. Safety
- WebAssembly runs in a sandboxed environment within the browser, providing a high level of security.
- It uses a memory-safe, sandboxed execution model to prevent malicious code from compromising the host environment.
3. Compatibility
- WebAssembly is designed to be platform-independent, allowing code to run consistently across different architectures and operating systems.
- It integrates seamlessly with existing web technologies like JavaScript, enabling interoperability with web applications.
4. Versatility
- WebAssembly can be used for a variety of use cases beyond web development, including server-side applications, game engines, and multimedia processing.
How WebAssembly Works
WebAssembly code is typically generated by compiling source code written in languages like C, C++, or Rust using specific compilers such as Emscripten or the Rust compiler with the wasm32-unknown-unknown
target.
Once compiled, the WebAssembly code can be executed within a web browser using the JavaScript-based WebAssembly runtime. Alternatively, it can be run outside the browser using standalone WebAssembly runtimes or integrated into existing software systems.
Use Cases of WebAssembly
WebAssembly has various applications across different domains:
- Web Development: Enhancing web applications with high-performance computations, multimedia processing, and gaming.
- Server-Side Applications: Running compute-intensive tasks efficiently on the server.
- Game Development: Building cross-platform games with near-native performance.
- Multimedia Processing: Processing and manipulating multimedia content such as images, audio, and video in the browser.
- Blockchain: Executing smart contracts and decentralized applications (DApps) on blockchain platforms.
Usage with Rust
Requirements
You need Rust installed and the following for creating the WebAssembly:
cargo install wasm-pack
Creating the project
Create a new library:
cargo new --lib hello-wasm
Sample src/lib.rs
:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
wasm-pack uses wasm-bindgen, another tool, to provide a bridge between the types of JavaScript and Rust. It allows JavaScript to call a Rust API with a string, or a Rust function to catch a JavaScript exception.
Calling external functions in JavaScript from Rust
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
As you might suspect, this is the alert function provided by JavaScript.
Whenever you want to call JavaScript functions, you can add them to this file, and wasm-bindgen takes care of setting everything up for you. Not everything is supported yet, but we're working on it.
Producing Rust functions that JavaScript can call
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
Once again, we see the #[wasm_bindgen]
attribute. In this case, it's not modifying an extern
block, but a fn
; this means that we want this Rust function to be able to be called by JavaScript. It's the opposite of extern
: these aren't the functions we need, but rather the functions we're giving out to the world.
This function is named greet
, and takes one argument, a string (written &str
), name
. It then calls the alert
function we asked for in the extern
block above.
Compiling our code to WebAssembly
To compile our code correctly, we first need to configure it with Cargo.toml
. Open this file, and change its contents to look like this:
[package]
name = "hello-wasm"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
description = "A sample project with wasm-pack"
license = "MIT/Apache-2.0"
repository = "https://github.com/yourgithubusername/hello-wasm"
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
The big part to add is the [package]
. The [lib]
part tells Rust to build a cdylib
version of our package.
The last section is the [dependencies]
section. Here's where we tell Cargo what version of wasm-bindgen
we want to depend on.
Building the package
Now that we've got everything set up, let's build the package. We'll be using the generated code in a native ES module and in Node.js. For this purpose, we'll use the --target
argument in wasm-pack build
to specify what kind of WebAssembly and JavaScript is generated.
wasm-pack build --target web
This does a number of things (and they take a lot of time, especially the first time you run wasm-pack
). In short, wasm-pack build
:
- Compiles your Rust code to WebAssembly.
- Runs
wasm-bindgen
on that WebAssembly, generating a JavaScript file that wraps up that WebAssembly file into a module the browser can understand. - Creates a
pkg
directory and moves that JavaScript file and your WebAssembly code into it. - Reads your
Cargo.toml
and produces an equivalentpackage.json
. - Copies your
README.md
(if you have one) into the package.
Using the package on the web
Now that we've got a compiled Wasm module, let's run it in the browser. Let's start by creating a file named index.html
in the root of the project, so we end up with the following project structure:
├── Cargo.lock
├── Cargo.toml
├── index.html <-- new index.html file
├── pkg
│ ├── hello_wasm.d.ts
│ ├── hello_wasm.js
│ ├── hello_wasm_bg.wasm
│ ├── hello_wasm_bg.wasm.d.ts
│ └── package.json
├── src
│ └── lib.rs
└── target
├── CACHEDIR.TAG
├── release
└── wasm32-unknown-unknown
Put the following content in the index.html
file:
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>hello-wasm example</title>
</head>
<body>
<script type="module">
import init, { greet } from "./pkg/hello_wasm.js";
init().then(() => {
greet("WebAssembly");
});
</script>
</body>
</html>
The script in this file will import the JavaScript glue code, initialize the Wasm module, and call the greet
function we wrote in Rust.
Serve the root directory of the project with a local web server, (e.g. python3 -m http.server
).
Note: Make sure to use an up-to-date web server that supports the
application/wasm
MIME type. Older web servers might not support it yet.
Load index.html
from the web server. An alert box appears on the screen, with Hello, WebAssembly!
in it. We've successfully called from JavaScript into Rust, and from Rust into JavaScript.