cover image
Web

Go in Web Applications with WebAssembly

With the advent of the new technology of WebAssembly, it is possible to leverage other languages than JavaScript in the browser. Go is one popular language that you can call from your JavaScript web application. This article shows how to do that with TinyGo.

About Go

Go is a statically typed, compiled programming language developed at Google by such computer pioneers like Ken Thompson. First released in 2009 it is popular with backend and systems programming tasks.

WebAssembly

WebAssembly defines a portable binary-code format that can be used to run high-performance application on web pages in languages other than JavaScript. WebAssembly code can interact with JavaScript code on a website. Currently, there exist several languages, like C, C++, C#, Rust and also Go which all compile to WebAssembly. Thus, the binary code of applications written in these languages can interact in the browser with JavaScript web pages. WebAssembly is currently supported on all major browsers.

TinyGo

TinyGo is an alternative implementation of the Go compiler, leveraging LLVM to optimize the generated code. It is able to target WebAssembly, and therefore I use it in this article.

You can read the installation instructions from the TinyGo website.

Web Application with Go

In order to show how to combine Go code with JavaScript, I use a NLP (Natural Language Processing) Go library that implements the Porter stemming algorithm.

Stemming in NLP is the process of reducing inflected and derived words to their root form. One widely used stemmer is the Porter stemmer, originally written by Martin Porter.

The Porter stemmer has applications in information retrieval and other linguistic and NLP tasks.

The Go code reads the data from the JavaScript DOM objects, where the user can enter the word to stem in an input field. Subsequently, the result of the stemming function is written back into the web page.

wasm.go

package main

import (
	"github.com/surgebase/porter2"
	"syscall/js"
)

func main() {
}

//export update
func update() {
	document := js.Global().Get("document")
	aStr := document.Call("getElementById", "word").Get("value").String()
	result := porter2.Stem(aStr)
	document.Call("getElementById", "result").Set("value", result)
}

The HTML web source code looks like this:

index.html

<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8" />
    <title>Go Porter Stemmer</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="wasm_exec.js" defer></script>
    <script src="wasm.js" defer></script>
  </head>

  <body>
    <h1>Porter Stemmer</h1>
    <p>Enter the word to stem:</p>
    <input id="word" /> = <input id="result" readonly />
  </body>
</html>

The JavaScript glue code calls the exported Go function update() with every keystroke:

wasm.js

'use strict';

const WASM_URL = 'wasm.wasm';

var wasm;

function updateResult() {
  wasm.exports.update();
}

function init() {
  document.querySelector('#word').oninput = updateResult;

  const go = new Go();
  if ('instantiateStreaming' in WebAssembly) {
    WebAssembly.instantiateStreaming(fetch(WASM_URL), go.importObject).then(function (obj) {
      wasm = obj.instance;
      go.run(wasm);
      updateResult();
    })
  } else {
    fetch(WASM_URL).then(resp =>
      resp.arrayBuffer()
    ).then(bytes =>
      WebAssembly.instantiate(bytes, go.importObject).then(function (obj) {
        wasm = obj.instance;
        go.run(wasm);
        updateResult();
      })
    )
  }
}

init();

The JavaScript file also contains a loading mechanism of the WebAssembly binary code that has been generated by the TinyGo compiler (wasm.wasm).

Before you can run this demo application, you need to compile the code with the TinyGo compiler. The Makefile copies the resulting WebAssembly files to the target html directory.

$ make demo

The accompanying Go web server can be started with

$ go run server.go
Serving ./html on http://localhost:8080

Now, you can use the website in your browser at http://localhost:8080.

As an example, you can enter the word "fishing" and it should return the stemmed form "fish".

And now you have combined Go code with a regular JavaScript application. This opens up a new, exciting world of Go and Go libraries to JavaScript web developers!

You can view and download the code of this application from my GitHub account under: https://github.com/tderflinger/tinygo-webapp-demo

Conclusion

The era of WebAssembly has already begun. It will possibly revolutionize many aspects of software development by enabling the combination of code in many programming languages on many platforms.

In this article, I hope I could show you that now it is possible to use Go code in your browser web application. This will enable you to leverage great existing Go code in your web applications.

References

  • Demo Application Source Code: https://github.com/tderflinger/tinygo-webapp-demo

  • Go: https://go.dev/

  • TinyGo: https://tinygo.org/

  • TinyGo WebAssembly examples: https://github.com/tinygo-org/tinygo/tree/release/src/examples/wasm

  • Porter2 Go Library: https://github.com/surgebase/porter2

  • WebAssembly: https://webassembly.org/

Published 29 Dec 2021
Thomas Derflinger

Written by Thomas Derflinger

I am a visionary entrepreneur and software developer. In this blog I mainly write about web programming and related topics like IoT.