Deploying and Using WebAssembly Under Deno on the Server Side Using Travis CI
Tags: news, feature, infrastructure, community
Published: 2021-01-07 11:05:23

---
title: "Deploying and Using WebAssembly Under Deno on the Server Side Using Travis CI"
created_at: Monday 04 Jan 2021 15:00:00 EDT
author: Montana Mendy
layout: post
permalink: 2021-01-04-wasm
category: news
excerpt_separator: <!-- more --> 
tags:
  - news
  - feature
  - infrastructure
  - community
---

![Header](https://dev-to-uploads.s3.amazonaws.com/i/8cddl3o7qpwnwty52jmo.png)

Containers are a game changer in software development. They provide the operational isolation found in virtual machines without the overhead. Whereas it can take a virtual machine minutes to spin up, you can have a container up and running in seconds, or even in some cases milliseconds.

<!-- more --> 

# Getting started

Containers have become central to modern distributed application architecture, particularly now that container orchestration technologies such as Kubernetes and Docker Swarm have become commonplace in the enterprise. However, as popular as container technology is for implementing isolated processes for use in a distributed application, there is an alternative. That alternative is [WebAssembly](https://webassembly.org/).


WebAssembly is a compiled binary that operates inside a runtime unit called a WebAssembly VM, or virtual machine. WebAssembly has been around for a while on the client side, and all the major web browsers support it. But you can also run it on the server side. All you need is to have a programming framework that supports server-side WebAssembly VM.

Deno — an emerging language from Ryan Stahl, the creator of Node.js — supports WebAssembly. Deno uses the V8 JavaScript runtime found in Chrome on the server side, as does Node.js. The WebAssembly VM is built right into V8, so Deno supports WebAssembly.

In this tutorial, I am going to show how to use Travis CI to build a WebAssembly binary written in Rust, and then run a demonstration application I wrote in Deno that uses the WebAssembly as an internal component.

This tutorial is high-level, and you don’t need to know the details of Rust or Deno to get benefit from reading it. The hope is that the tutorial will spur your interest to delve further into the technologies.

## Understanding the demonstration application

The [demonstration project](https://github.com/reselbob/deno-wasm) that accompanies this article is a Deno application that uses a WebAssembly binary. The Deno code uses logic in the WebAssembly to do a calculation. The calculation that the WebAssembly binary provides is encapsulated into a function named cube(). The function cubes a number that is provided as a parameter. For example, when the number 3 is passed to the function, as cube(3), the function returns 27.

As shown in figure 1 below, the WebAssembly (WASM) binary is written in the programming language [Rust](https://www.rust-lang.org/). Rust is a compiled language. A programmer writes some code in text and stores it in a file named lib.rs. The code is passed to the Rust WASM compiler. The result is a WebAssembly binary that’s used by the Deno code.

![Fig1](https://dev-to-uploads.s3.amazonaws.com/i/fcpm4qbfvo1h14u19a80.png)

> Figure 1: Deno uses a WebAssembly binary programmed in Rust.

That’s the high-level view. Let’s take a look at some of the detail involved in creating the WebAssembly binary in Rust and then consuming the binary in Deno.

## Examining the WebAssembly code

The work required to create a WebAssembly binary in Rust is consolidated using Rust’s `crate` packaging technology.

The Rust programming community provides a packaging ecosystem similar to [npm](https://www.npmjs.com/) for Node.js and to Java’s [Maven](https://maven.apache.org/what-is-maven.html). Packages under Rust are called `crates`. The standard file that describes a crate is named [`Cargo.toml`](https://doc.rust-lang.org/cargo/reference/manifest.html). It’s similar to the way Node.js uses [package.json](https://docs.npmjs.com/files/package.json) to describe a Node.js package. (I’ll explain the `Cargo.toml` file for the demonstration Rust binary in a moment.)

The way you install Rust packages from an external Rust package repository is to use the command [cargo install <crate_name>](https://doc.rust-lang.org/cargo/commands/cargo-install.html).

Creating a WebAssembly in Rust can be a detail-laden undertaking. To simplify the process, we’re going to use an external package called wasm-pack. [wasm-pack](https://rustwasm.github.io/wasm-pack/book/) will execute against the Cargo.toml file that defines the WebAssembly binary we’re going to create. (Keep in mind that the standalone WebAssembly binary is considered a package.)

Listing 1 below shows the Cargo.toml file that describes the Rust project. 

```rust
[package]
name = "cube_it"
version = "0.9.0"
edition = "2018"
authors = ["Bob Reselman <reselbob@gmail.com>"]
description = "A small project to demonstrate how to run to create a WebAssembly binary"
license = "MIT/Apache-2.0"
repository = "https://github.com/reselbob/deno-wasm"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wasm-bindgen = "0.2"

[lib]
crate-type = ["cdylib", "rlib"]
```
> Listing 1: The Cargo.toml file

Lines 1 through 12 above provide typical metadata about the project. Notice in line 1 that the arbitrary name of the package is `cube_it`. This makes sense because the WebAssembly binary that this package definition creates has a function that will cube a number.

Lines 13 and 14 indicate that the Rust project will use an additional package, wasm-bindgen. The purpose of wasm-bindgen is to provide interoperability between the Rust binary and JavaScript code. Deno programming is done in TypeScript. However, at runtime TypeScript [transpiles](https://encyclopedia2.thefreedictionary.com/transpile) into JavaScript. Using `wasm-bindgen` allows the Rust code to access JavaScript functions such as logging and the JavaScript DOM model, so `wasm-bindgen` is defined in `Cargo.toml`.

Lines 16 and 17 assign the library [cdylib](https://doc.rust-lang.org/nightly/edition-guide/rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.html) to crate-type. This provides interoperability with C code. In addition, crate-type is assigned the value [rlib](https://doc.rust-lang.org/reference/linkage.html) to indicate that a Rust library will be produced.

Listing 2 below shows the Rust code for the function `cube(x: u32)`. The function will reside in the file `lib.rs`.

```rust
#[no_mangle]
pub extern "C" fn cube(x: u32) -> u32 {
    x * x * x
}
```
> Listing 2: The Rust code in `lib.rs` that publishes the cube function

The logic in the function `cube(x: u32)` will be consumed by the Deno code.

Once the Rust package is declared in `Cargo.toml` and the `cube()` function is defined in `lib.rs`, we’ll need to create the Deno code to consume the WebAssembly binary that’s created.

## Running WebAssembly under Deno

Listing 3 below shows the contents of the file [`main.ts`](https://github.com/reselbob/deno-wasm/blob/master/main.ts). This file contains the Deno code that consumes the WebAssembly binary that contains the function `cube()`.

```rust
const wasmCode = await       Deno.readFile("./rust_for_deno/target/wasm32-unknown-unknown/release/cube_it.wasm");
const wasmModule = new WebAssembly.Module(wasmCode);
const wasmInstance = new WebAssembly.Instance(wasmModule);
const {cube} = wasmInstance.exports;

console.log(cube(1));
console.log(cube(2));
console.log(cube(3));
console.log(cube(4));
```

> Listing 3: The Deno code that consumes the WebAssembly binary

Lines 1 through 5 do the work of loading the WebAssembly into the V8 virtual machine and making the `cube()` function accessible to the Deno code. Lines 7 through 10 execute the `cube()` function four times, each time with a different parameter value, and then write the output of each call to the console.

Now that we have both the Rust WebAssembly and Deno projects coded and ready to go, we need to create a `travis.yml` file that will build the WebAssembly binary, as well as install the Deno runtime environment and run the Deno code.


## Working with the `.travis.yml` file

One of the nice features of Travis CI is that it will execute a run script in response to an event generated from a webhook installed in a GitHub repository that is bound to Travis CI. Under Travis CI, the run script has a standard name, `.travis.yml.`

The [deno-wasm](https://github.com/reselbob/deno-wasm) demonstration project for this article stored on GitHub has a webhook installed that sends an event notification to Travis CI whenever code is committed to the `deno-wasm` repository. Travis CI receives the event notification and clones the code into a runtime virtual machine created just for the project. Then, it runs the instructions in the expected `.travis.yml` file.


Listing 4 below shows the contents of the `.travis.yml` file.

```yaml
language: rust
os: ubuntu
branches:
    only:
    - master
before_install:
    - pwd
    - rustc --version
    - sudo apt-get update
    - sudo apt-get -y install libssl-dev pkg-config 
    - rustup target add wasm32-unknown-unknown
    - cargo install wasm-pack
    - export PATH="$HOME/.cargo/bin:$PATH"
    - cd ./rust_for_deno
    - wasm-pack build
    - cd ..
    - curl -fsSL https://deno.land/x/install/install.sh | sh
    - ls -l $HOME/.deno
    - export DENO_INSTALL="$HOME/.deno"
    - export PATH="$DENO_INSTALL/bin:$PATH"
    - deno run https://deno.land/std/examples/welcome.ts
    
script: 
    - deno run --allow-read main.ts
```
> Listing 4: The travis.yml file for building and running the deployment on Travis CI

The first thing to notice about the `.travis.yml` file in listing 4 above is that Travis CI supports the Rust programming language right out of the box. All you need to do is set the `language` definition, as shown at line 1.

The work of creating the WebAssembly binary and installing Deno is done in the `before_install` section, starting at line 5.

Lines 7 and 8 are convenience instructions that report the present working directory `(pwd)` and the current version of the Rust compiler installed `(rustc --version)`. This is done just to make sure that the `.travis.yml` script is talking to the Travis CI runtime in a predictable manner.

Lines 9 and 10 install some added packages that Ubuntu needs in order to execute the `wasm-pack` instruction that will come.

Lines 11 through 15 do the work of installing the `wasm-pack` Rust package and creating the WebAssembly binary using `wasm-pack`.

Deno is not installed in the Travis CI runtime environment by default. Thus, lines 17 through 20 do the work of installing it and configuring the `DENO_INSTALL` environment variable. Also, the `PATH` environment variable is updated to accommodate the Deno binaries.

Line 21 runs a Deno `Hello World` program downloaded from the internet, to verify that Deno is up and running.

As mentioned earlier, the code that uses the `cube()` function in the WebAssembly binary is stored in the file `main.ts`. `main.ts` is called within the script section of the `.travis.yml` file at line 24 above.

The output of the call to the `main.ts` file is shown below in figure 2.

![Fig2](https://dev-to-uploads.s3.amazonaws.com/i/e9xc5m0qticd22p287q3.png)

> Figure 2: The output from the demonstration application running under Travis CI

So there you have it. We’ve just used the Travis CI runtime environment to create a WebAssembly binary and run it in a Deno program. Granted, this is just a small demonstration program, but it does reveal the critical aspects of using WebAssembly to provide services to interested consumers in an isolated manner.

## Putting it all together

It’s interesting that Solomon Hykes, the co-founder of Docker, [said this](https://conferences.codegram.com/talks/bringing-webassembly-outside-the-web-with-wasi-fsf2019) about WebAssembly:

"_“If WASM+WASI [WebAssembly and its system interface] existed in 2008, we wouldn’t have needed to create Docker._"

Server-side WebAssembly has significant potential. Its elegance and power make it an attractive technology for the fast execution of complex algorithms on the server side. Consequently, there are a growing number of projects that are publishing tools for WebAssembly development. You can already create WASM binaries in Go, Rust, C# and C/C++. In addition, there are initiatives to bring support for WebAssembly to a wider array of languages. For example, [AssemblyScript](https://www.assemblyscript.org/) is intended to allow developers to create WebAssembly binaries from JavaScript code.

The opportunities at hand are significant. Of course, in order to make WebAssembly a viable addition to your programming toolbox, you will need to take the time to master the details of the technology. But, as current trends reveal, WebAssembly is becoming a mainstay on the server side, and realizing its value will be an investment that will yield dramatic returns.

WebAssembly is here. The time to take advantage of the opportunities at hand is now.