What is WebAssembly?
WebAssembly is a compilation target for C, C++, Go, and Rust among others. Developers can code in any of those languages and then compile their source into Wasm binaries. These then run alongside JS code in their apps.
That means that there is less overhead when accessing variables or evaluating expressions (there is no OrdinaryGetOwnProperty madness).
However, none of these is the factor that makes WebAssembly so special. After all, on a purely technical level, Wasm binary is not very different from Java’s bytecode or .NET Common Intermediate Language.
But WebAssembly is an open standard and is already implemented in all the major browsers. Consequently, you don’t need a native plug-in to run Wasm code in your browser, no matter what platform, OS, or device you are using – that’s pretty unique.
Several revisions of the ECMAScript standard have been released to improve the language and address its limitations. Furthermore, new and more expressive languages (yes TypeScript, we hear you) have been released to add missing features while maintaining complete compatibility with existing runtime engines.
All of this has led to the fragmented ecosystem we all have to struggle with everyday, making the development of large projects very challenging.
Therefore, when in need of native performance, developers have had to turn to native code (plug-ins, NPAPI, etc.), often with disastrous consequences in terms of security. This is where WebAssembly functions come to the rescue of our programming.
Writing Rust targeting WebAssembly
Golang would be a better alternative in this case, as it is concise and easy to read. However, there is always a trade-off between performance and readability. Go’s runtime offers a lot of features, but these come at the cost of the binary size: the smallest Wasm file compiled from Go is around 2 MB, while 10 MB is typical. That is huge compared to files compiled from C++ and Rust code, which are typically just a few KB.
What is Rust?
Rust is an open-source multi-paradigm programming language that focuses on speed, memory safety and parallelism. It eliminates many classes of bugs at compile-time and it is used in performance-critical services and embedded devices. Rust also integrates with other languages.
WebAssembly tutorial: setup
To begin programming with Rust and WebAssembly, one must obviously have the Rust toolchain installed. The best (and recommended) way to manage the Rust toolchain is via the rustup tool.
Installing rustup is as easy as launching a Bash script (the rustup-init.sh script, in fact) with this one-line command:
# curl https://sh.rustup.rs -sSf | sh
If you are running Windows, luckily we live in the era of Nadella, and thus have plenty of options to get Bash up and running: the Windows Subsystem for Linux, Git for Windows’ own Bash, or Cygwin, just to name a few.
If you don’t want to use Bash at all, there is an .exe version of rustup-init as well as standalone installers available for download from the Rust code language project website.
The script will download and compile all the required tools including rustc (the Rust compiler) and cargo (Rust’s package manager).
The toolchain will be installed by default in $HOME/.cargo so be sure to add the $HOME/.cargo/bin to your PATH environment variable, or simply run the command
# source $HOME/.cargo/env
when opening a new shell.
Once the Rust toolchain is installed, we can proceed with installing Wasm-pack. Wasm-pack is an all in one tool to build, test and publish Rust-generated Wasm modules. To install it, simply type this command in your Bash prompt:
# curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
Alternatively, you can again download the .exe file from the official website if you are on Windows.
Another useful tool to install is
cargo-generate, which allows the creation of new projects based on existing templates.
Since the Rust toolchain is already installed, we can use Cargo it-self to download, compile and install cargo-generate, with this command:
# cargo install cargo-generate
If you do not already have them installed, we recommend installing git, node and npm – these may come in handy pretty soon.
Our first WebAssembly module
Let’s dive in and build our first Hello World project in Rust Wasm: a web page that shows an alert!
First of all, we will create a new project using cargo generate, using a git repository as a template:
# cargo generate --git https://github.com/rustwasm/wasm-pack-template
When prompted for the project’s name, just type ‘hello’. The script will create the directory ‘hello’ and populate it with the files shipped with the template:
- Cargo.toml – specifies dependencies and metadata for cargo (a sort of Rust equivalent of package.json);
- src/lib.rs – contains the code of our Wasm module;
- src/utils.rs – provides common utilities to debug Wasm code;
Let’s have a look at the lib.rs code in detail:
In this simple example, wasm_bindgen is used to import the browser’s alert() function, so our Rust code can call it and display the “Hello, hello!” message (the string created by cargo generate is “Hello, <project_name>!” and our project is named “hello”). Feel free to change this message according to your preferences.
When targeting Wasm, the wee_alloc allocator is the preferred choice, as it was explicitly designed for smaller code size, although it can be a bit slower than other allocators.
# wasm-pack build
Once finished, the compiled artifacts are available in the pkg/ directory. This directory should contain these files:
- hello_bg.wasm – our WebAssembly binary, which exports the greet() function;
- package.json – the metadata about this generated WebAssembly package;
Calling WebAssembly from a web page
The Rust project offers an npm init template to generate a web application that will call our WebAssembly module. Simply type the command:
# npm init wasm-app www
To use our WebAssembly package here, we simply add it as a dependency in the package.json file, by adding the following line under the “devDependencies” node:
Then, install the dependencies with the well known command:
# npm install
Once the installation is finished, modify the index.js file to call our WebAssembly greet() function, with this code:
import * as wasm from "hello"; wasm.greet();
As we have Webpack and its local server installed, we can run the app with the command:
# npm run start
Now point your browser to http://localhost:8080/ to be greeted with the message from our Rust code.
Congratulations, you have created your first Rust/WebAssembly project!
What is he future of WebAssembly?
Google called WebAssembly the “future of the web”. That says enough. There are some undoubtful advantages to using Wasm. For starters, it can be executed at near-native speed across different platforms.This is possibile bacause it is statically typed, uses linear memory, and is stored in binary format.
Also, it runs in a safe sandboxed environmentit, is compatible with other web technologies and maintains backwards compatibility.
If you want to try WebAssembly without C or Rust, AssemblyScript will be the best option. If you want to learn more about Rust and WebAssembly, don’t miss the talk Diwanshi Pandey, software engineer at Red Hat, gave at the Codemotion Conference. Diwanshi addressed more advanced topics and showed some really interesting demos.