Wasmer takes WebAssembly libraries mainstream with WAI
Import WebAssembly libraries just like any other dependency in your project
Syrus Akbary
Founder & CEO
December 2, 2022
Integrating with other languages and distributing binaries has always raised the WebAssembly's barrier to entry for the average developer, and at Wasmer our goal is to make trivial creating universal libraries that work anywhere.
Today, we are happy to announce Wasmer Pack, a tool which integrates with the WebAssembly Package Manager and WebAssembly Interfaces ("WAI") to create packages that can be imported from other languages.
Note: WAI builds on top of the WebAssembly Interface Types specification and its first working implementation,
wit-bindgen
. Unfortunately, the maintainers behindwit-bindgen
were reluctant to allow integration of Wasmer upstream, so we've forked the project under a new name.A key difference between WAI and
wit-bindgen
is the focus on stability - people should be able to start using WAI right now.
The WAI addition to the WebAssembly Package Manager streamlines the way developers use WebAssembly in their applications by automatically generating installable packages for your language of choice.
In fact, you can see it in action right now with the vscode-wasm
plugin which uses the automatically generated wabt WAI bindings, used by more than 94 thousand developers worldwide!
WAPM is not tied to just the WAI format though, we are working to allow integrating any kind of Wasm bindings into the Package Manager (such as Extism)... if you maintain a binding format we want to hear from you!
How Do I Create a Universal WebAssembly Library with Rust and WAI?
Everything revolves around WAI files.
These define the WebAssembly Interfaces your library will expose, and from there our tooling will generate some glue code that makes it easier to implement.
First, create a new Rust project and add the wai-bindgen-rust
crate as a dependency.
$ cargo new --lib tutorial-01
$ cd tutorial-01
$ cargo add wai-bindgen-rust
Now, let's define a WAI file that lets us add two floating point numbers.
// calculator.wai
/// Add two numbers.
add: func(a: float32, b: float32) -> float32
We can use the wai_bindgen_rust::export!()
macro to "export" this interface (i.e. make it available to some host application).
// src/lib.rs
// generate the WAI glue code under the `calculator` module
wai_bindgen_rust::export!("calculator.wai");
// Create a type to attach our functionalty to
struct Calculator;
// Implement the trait generated by our glue code
impl crate::calculator::Calculator for Calculator {
fn add(a: f32, b: f32) -> f32 { a + b }
}
💡 You can use cargo expand
to see the generated code and the Calculator
trait's definition (cargo install cargo-expand
).
Let’s publish it!
Publishing requires installing wapm
with the Wasmer installer and the cargo wapm
helper installed (cargo install cargo-wapm
). If you haven't already, make sure to run wapm login
to log into your WAPM account (don't forget to sign up if you haven't already).
Now we're set up, we'll need to update Cargo.toml
so this package can be published to WAPM.
# Cargo.toml
[package]
name = "tutorial-01"
version = "0.1.0"
description = "A simple calculator"
[package.metadata.wapm]
namespace = "<YOUR_USERNAME>" # The namespace to publish it to
abi = "none" # How to compile the crate. "none" is "wasm32-unknown-unknown"
bindings = { wai-version = "0.2.0", exports = "calculator.wai" }
Now we need to tell the Rust compiler to generate a cdylib
("C-compatible
dynamic library"). It's also a good idea to add the rlib
crate type so
integration tests can import the library as a Rust dependency.
# Cargo.toml
[lib]
crate-type = ["cdylib", "rlib"]
And publish!
$ cargo wapm
Note: WAI also works with other languages, such as C or C++. If you want to publish packages to WAPM with it, you will need to use wapm publish
instead of cargo wapm
.
Consuming WAPM Packages in your codebase
Let's add this wai/tutorial-01
package to a JavaScript project.
First, we'll need to create a new JavaScript package and add the wai/tutorial-01
package as a dependency.
$ wasmer add --yarn wai/tutorial-01
This runs yarn add
under the hood. Depending on the project, you might use the --npm
flag to do npm install
or --pip
for pip install
.
Now, let's create a script.
import { bindings } from 'wai/tutorial-01';
async function main() {
const calculator = await bindings.calculator();
const four = calculator.add(2, 2);
console.log('2 + 2 =', four);
}
main();
Or, if you want to do it in python:
$ wasmer add --pip wai/tutorial-01
from tutorial_01 import bindings
calculator = bindings.calculator()
print("2+2 = ", calculator.add(2.0, 2.0))
What's Next?
If you've been hesitant to use WebAssembly because it's hard to get started, go ahead and check out our tutorial series!
WAPM uses the Wasmer Pack project to generate these native packages. Feel free to browse the source code, or create tickets on the issue tracker if you have any questions.
We'd love to hear from projects looking to integrate WAPM packages into their own apps. If this sounds like you, reach out on Slack, by email, or the Wasmer Pack issue tracker, and we'll help you get started.
About the Author
Syrus Akbary is an enterpreneur and programmer. Specifically known for his contributions to the field of WebAssembly. He is the Founder and CEO of Wasmer, an innovative company that focuses on creating developer tools and infrastructure for running Wasm
Syrus Akbary
Founder & CEO
How Do I Create a Universal WebAssembly Library with Rust and WAI?
Let’s publish it!
Cargo.toml
Cargo.toml
Consuming WAPM Packages in your codebase
What's Next?
Read more
EngineeringbindingsC
Novel way to Develop, Test and Document C libraries from Rust
Syrus AkbaryJuly 6, 2021