Originally published at five.co blog
"WebAssembly will replace Javascript" - I have read this so many times in these internet streets, and that has made me curious about the possibility of making full-stack web applications with WebAssembly. First, to calm your nerves, it is currently not possible to use WebAssembly in the browser for web applications without some Javascript glue code, more on "Glue Code" later, but there is a lot of things you can already do in the browser with WebAssembly, which you could only do with Javascript in the past. How about i take you on a journey, as we explore WebAssembly, and how you can take advantage of it's features as a Javascript developer. Most of the things discussed also extend to Rustaceans, gophers, pythonians and whatever C++ developers are called. At the end of this article, i will also show you how you can hook up a small Javascript script to a WASM binary and execute a simple Rust program. So come along as we explore....
WebAssembly, or WASM for short, is a new technology that has been gaining a lot of attention in recent years. It is a low-level, binary instruction format for a stack-based virtual machine (VM). It is designed as a portable target for the ahead-of-time (AOT) compilation of high-level languages such as C, C++, and Rust, enabling deployment on the web for client-side and server-side applications.
Okay, that feels like a lot of buzzwords. In simpler terms: Webassembly is a fancy new virtual machine that now ships with all web browsers, well almost all browsers (looking at you Internet Explorer 11 and Opera Mini!) that allows you to run performance-critical business-logic code at blazingly fast speed. Of course we can put a lot of logic in our Javascript frontends using our trusty client-side rendering frameworks, or we can just put our logic in a nodejs backend and communicate with it from the frontend using APIs, right?
Well yes, and that is how it has been done before WebAssembly joined the party, but remember when i said "performance-critical" business-logic? WebAssembly does not advertise itself as another scripting environment to make buttons animate or submit forms, but as an alternative for running heavy workloads at near-native speed. Remember when app developers would say "web browsers will never run progressive-web-apps (PWAs) as fast as native applications"? Well, not quite so anymore.
The problem with using a dynamically-typed, interpreted programming language (Javascript) for writing business-logic for performance-critical applications is that it's just plain dificult to achieve any decent performance or to even get it running in the browser at all.
With WebAssembly, you can perform complex computations at near-native speeds. JavaScript is a dynamically typed, interpreted language, which means that it can be slow when performing complex operations. WebAssembly, being a statically typed, compiled language, allows complex computations to run much faster than JavaScript. This makes WebAssembly a great option for tasks such as video rendering, 3D graphics, and other computationally intensive operations.
WebAssembly allows for improved security and sandboxing. JavaScript is a high-level language and is executed by the browser's JavaScript engine, which can be vulnerable to attacks. WebAssembly, on the other hand, is executed by the browser's WebAssembly engine, which is more secure and can be sandboxed to prevent malicious code from running. This makes WebAssembly a great option for web-based tasks such as online banking, payment processing, online gaming, and secure document signing, which require a high level of security.
The best thing about WebAssembly is its ability to interact with other programming languages. WebAssembly modules can be written in any language that can be compiled to WebAssembly bytecode, such as C, C++, Rust, and more. This allows developers to use their preferred language for a specific task, and then seamlessly integrate it into a web application using WebAssembly. This can be especially useful for developers who are already familiar with a particular language and want to use it for web development.
For JavaScript developers, the rise of WebAssembly may seem like a daunting prospect. As more and more web frameworks written in programming languages like Rust, Go, and C++ are developed, it becomes increasingly easy for developers to write frontends in languages other than JavaScript.
One example of a framework that utilizes WebAssembly is Yew, a modern Rust framework for creating web apps. Yew allows developers to write safe and performant code that can be compiled to WASM and run directly in the browser. This means that Rust developers can now build web apps without having to learn JavaScript.
Another example is GopherJS, a transpiler that allows developers to write front-end code in Go and then compile it to JavaScript. This means that Go developers can also build web apps without having to learn JavaScript.
Similarly, C++ developers can now use the C++ WebAssembly Framework (CWasm) to build web apps. CWasm is a C++ library that provides a C++ interface to the WebAssembly virtual machine, making it easy for C++ developers to write web apps that run on the browser.
The emergence of these frameworks indicates that WebAssembly is becoming a viable alternative to JavaScript for front-end web development. This is a scary prospect for JavaScript developers as it means that their skills may become less in demand in the future.
However, it is important to note that JavaScript is still the most widely-used programming language on the web and it is unlikely to be replaced entirely by WebAssembly. Instead, WebAssembly will likely be used to complement and enhance the capabilities of JavaScript.
You know i can't leave you without some code. Let's try to write a simple WASM binary written in 6 lines of Rust, and then run it in a web browser using only 11 lines of Javascript. I also added a link to an already compiled WASM binary in case you don't want to write 6 lines of Rust. Here is a step-by-step guide:
You can install Rust using the rustup script. Just run the below in your terminal:
curl https://sh.rustup.rs -sSf | sh
wasm-pack is the Rust library which we will use to compile Rust into WASM. If you installed Rust, then you already have Cargo installed. Run the following to install wasm-pack:
cargo install wasm-pack
Next, you need to create a new Rust project. Run the following command in your terminal to create a new Rust project with the name "wasm_example":
cargo new --lib wasm_example
After that, you need to add the wasm-bindgen library to your Cargo.toml
file, which was generated by Cargo. This library will allow you to interact with JavaScript in your Rust code. Add the following line to your Cargo.toml
file in the dependencies section:
wasm-bindgen = "0.2"
your Cargo.toml
should look like this:
[package]
name = "wasm_example"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "0.2"
don't forget to add:
[lib]
crate-type = ["cdylib", "rlib"]
as demonstrated above
Now, you need to write your Rust code. In the src
directory, open the lib.rs
file and write your Rust code. We want a very simple Add
function that takes two integers as arguments and returns their sum:
use wasm_bindgen::prelude::wasm_bindgen;
#[wasm_bindgen]
pub fn add(left: usize, right: usize) -> usize {
left + right
}
Next, you need to use the wasm-pack
tool to compile your Rust code to WebAssembly. Run the following command in your terminal:
wasm-pack build
Once the compilation is complete, you will find a pkg
directory in your project. Inside the pkg
directory, you will find some JavaScript files and a WebAssembly file.
Now you will need to write a JavaScript file that will interact with your WASM code. Create a new file glue.js
in your project directory and write the following in it:
// Load the WebAssembly module
const importObject = {};
const path_to_wasm = "./pkg/wasm_example_bg.wasm";
fetch(path_to_wasm)
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, importObject))
.then(results => {
const wasm = results.instance.exports;
// Call a function exported by the WebAssembly module
console.log(wasm.add(20, 4));
});
In order to run anything in the browser, we need a HTML file. Create a new file index.html
in your project directory and write the following in it:
<!DOCTYPE html>
<html>
<head>
<title>WASM example</title>
<script src="./glue.js"></script>
</head>
<body>
</body>
</html>
To run it in your browser, you could just open the HTML file in your browser, but you might encounter some CORS issues, so I'll recommend you use a simple tool called "http-server" to serve your static files. If you have nodejs installed, you can install it using:
npm install http-server -g
Now that you have it installed, simply run http-server
in your project directory and you will be given a URL which you can open in your browser.
You see a blank screen and you wonder why? well, remember we didn't write anything fancy in our HTML file? we need to open the console of the browser to see the result of our addition.
If everything worked fine, you should see a number printed in the console, which should be the sum of the two numbers we passed to the function in glue.js
at console.log(wasm.add(20, 4));
. you can change these numbers to get a different sum. Congratulations! you just made your first WASM project!
If you change the numbers and you still get the same number printed in the console, it is because your browser is caching the javascript. You can force-reload the page by holding shift and hitting the refresh button while the console is open.
All of the code is in this Github repository. Feel free to use it and play with it.
In case you hate Rust or don't want to write the Rust code, no worries. I have compiled the Rust code for the JS devs to play with. The output of the wasm-pack build
command are all located in the pkg
folder in the above repository. Thank me later!
WebAssembly is a powerful new technology that has the potential to supplement and enhance the capabilities of JavaScript. While it is unlikely that JavaScript will be completely replaced by WebAssembly, it can be used to perform complex computations at near-native speeds, interact with other programming languages, and provide improved security and sandboxing. As web development continues to evolve, it is likely that WebAssembly will play an increasingly important role in the development of web applications. Developers who are looking to expand their skills and stay ahead of the curve should consider learning WebAssembly and experimenting with its capabilities.
Thank you for reading,
Give me a follow on Twitter to get updated on my new articles, and join my Discord server if you would like to see cool open-source projects i am building with an awesome community of software enthusiasts.
Consider donating, or becoming a sponsor to help me transition into making open-source software, full-time.