Get Started with WebAssembly using TypeScript: Part 2

Get Started with WebAssembly using TypeScript: Part 2

In part 1 of this series, we looked at taking some TypeScript code, compiling it with the subo CLI and AssemblyScript toolchain to create a WebAssembly module. WebAssembly is incredibly useful as it allows us to create modules that can be executed in a wide variety of environments such as cloud, edge, browsers, and more. In this post, we're going to take that WebAssembly module and embed it into a Go application; we're going to run TypeScript inside Go!

In part 3 we'll turn things up a notch with some WebAssembly capabilities, part 4 will take a look at WebAssembly in the browser, and we'll wrap up in part 5 by building a server-side API entirely powered by Wasm modules! Without further ado, let's get into it.

The scheduler

To run our Wasm module in Go, we're going to use the Reactr function scheduler. A scheduler is a library that helps you execute a large amount of work and lets the library determine the most efficient way to accomplish that work. Schedulers are designed to run your program with the highest possible performance while preventing your program from overwhelming the machine it's running on.

Before we continue, make sure you have Go installed. Let's head back to our myfirstmodule directory from part 1 and create a file called main.go. It should look something like this:

package main

import (
    "github.com/suborbital/reactr/rt"
)

func main() {
    r := rt.New()
}

Once you've got your main.go, you'll want to initialize a Go module and install Reactr as a dependency:

go mod init github.com/{username}/myfirstmodule
go mod tidy

This should create a go.mod and go.sum file.

Register the module

To use Reactr, we'll want to register our WebAssembly module as something we can execute. Reactr calls these Runnables, and they can either be Go code or Wasm modules. Let's use the rwasm package to register our module:

package main

import (
    "github.com/suborbital/reactr/rt"
    "github.com/suborbital/reactr/rwasm"
)

func main() {
    r := rt.New()

    r.Register("myfirstmodule", rwasm.NewRunner("./myfirstmodule.wasm"))
}

You may need to run go get after adding the rwasm import to install it.

Execute some WebAssembly!

Now that the module is registered, we can give it some work to do:

package main

import (
    "fmt"
    "log"

    "github.com/suborbital/reactr/rt"
    "github.com/suborbital/reactr/rwasm"
)

func main() {
    r := rt.New()

    doMyModule := r.Register("myfirstmodule", rwasm.NewRunner("./myfirstmodule.wasm"))

    result, err := doMyModule("world").Then()
    if err != nil {
        log.Fatal(err)
    }

    resultBytes := result.([]byte)

    fmt.Println(string(resultBytes))
}

What we did here is tell Reactr to execute our Wasm module and pass it the string "world" as input. If you remember from our TypeScript code:

import { logInfo } from "@suborbital/suborbital"

export function run(input: ArrayBuffer): ArrayBuffer {
    let inStr = String.UTF8.decode(input)

    let out = "hello, " + inStr

    logInfo(out)

    return String.UTF8.encode(out)
}

The function takes bytes as input, and logs and returns "hello, " + inStr. So let's run our program and see what happens!

go run main.go
{"log_message":"(I) hello, world","timestamp":"2021-07-23T09:54:09.907363-04:00","level":3,"scope":{"ident":953907866}}
hello, world

And there we have it! Reactr is loading our Wasm module, scheduling some work to be executed, and then our TypeScript code is handling that work by printing a log message and then returning a value to us.

What's next?

This is just the beginning of what WebAssembly can do. In part 3 we'll look at the capabilities your Wasm code can access such as making HTTP requests, accessing a cache, and more. This Foundations series will continue by giving you everything you need to take advantage of Wasm in the real world! Keep an eye on our Twitter account for the next few parts, and sign up for our newsletter below to get regular updates about WebAssembly, cloud native, and our open source projects.

Cover photo by Artyom Korshunov on Unsplash