Modal Title
Software Development / WebAssembly

WebAssembly and Go: A Guide to Getting Started (Part 1)

WebAssembly is a binary instruction format designed for web browsers, while Golang is known for its simplicity, speed and concurrency features. The first of a two-part series shows how they work together.
Jun 12th, 2023 5:00am by
Featued image for: WebAssembly and Go: A Guide to Getting Started (Part 1)
Image by Alex King from Unsplash. 
Editor’s note: This is Part One of a two-part series on WebAssembly and the programming language Go. You can read the second part here.

WebAssembly (Wasm) and Go are a powerful combination for building efficient and high-performance web applications. WebAssembly is a portable and efficient binary instruction format designed for web browsers, while Go is a programming language known for its simplicity, speed and concurrency features.

In this article, we will explore how WebAssembly and Go can work together to create web applications that leverage the benefits of both technologies. We will demonstrate the steps involved in compiling Go code into Wasm format, loading the resulting WebAssembly module into the browser, and enabling bidirectional communication between Go and JavaScript.

Using Go for WebAssembly offers several advantages. First, Go provides a familiar and straightforward programming environment for web developers, making it easy to transition from traditional Go development to web development.

Secondly, Go’s performance and concurrency features are well-suited for building efficient web applications that can handle heavy workloads.

Finally, the combination of Go and WebAssembly allows for cross-platform compatibility, enabling the deployment of applications on various browsers without the need for plugins or additional dependencies.

We will dive into the technical details of compiling Go code to Wasm, loading the module in a web browser, and establishing seamless communication between Go and JavaScript for WebAssembly.

You’ll come away with a comprehensive understanding of how Wasm and Go can be leveraged together to create efficient, cross-platform web applications. Whether you are a Go developer looking to explore web development or a web developer seeking high-performance options, this article will equip you with the knowledge and tools to get started with WebAssembly and Go.

Go and Its Use Cases

Go is often used for server-side development, network programming and distributed systems, but it can also be used for client-side web development.

Web development. Go is a popular choice for web development due to its simplicity, speed and efficient memory usage. It is well-suited for building backend web servers, APIs and microservices. Go’s standard library includes many built-in packages that make web development easy and efficient. Some popular web frameworks built in Go include Gin, Echo and Revel.

System programming. Go was designed with system programming in mind. It has a low-level feel and provides access to system-level features such as memory management, network programming and low-level file operations. This makes it ideal for building system-level applications such as operating systems, device drivers and network tools.

DevOps tools. Go’s simplicity and efficiency make it well-suited for building DevOps tools such as build systems, deployment tools, and monitoring software. Many popular DevOps tools are built in Go, such as Docker, Kubernetes, and Terraform.

Machine learning. Although not as popular as other programming languages for machine learning, Go’s performance and concurrency features make it a good choice for building machine learning models. It has a growing ecosystem of machine learning libraries and frameworks such as Gorgonia and Tensorflow.

Command-line tools. Go’s simplicity and fast compilation time makes it an ideal choice for building command-line tools. Go’s standard library includes many built-in packages for working with the command-line interface, such as the “flag” package for parsing command-line arguments and the “os/exec” package for executing external commands.

Key Benefits of Using WebAssembly with Go

Performance. WebAssembly is designed to be fast and efficient, which makes it an ideal choice for running computationally intensive tasks in the browser. Go is also known for its speed and efficiency, making it a good fit for building high-performance web applications.

Portability. Wasm is designed to be portable across different platforms and architectures. This means that you can compile Go code into WebAssembly format and run it on any platform that supports WebAssembly. This makes it easier to build web applications that work seamlessly across different devices and operating systems.

Security. WebAssembly provides a sandboxed environment for running code in the browser, which helps to prevent malicious code from accessing sensitive user data. Go also has built-in security features such as memory safety and type safety, which can help to prevent common security vulnerabilities.

Concurrency. Go is designed with concurrency in mind, which makes it easier to build web applications that can handle multiple requests simultaneously. By combining WebAssembly and Go, you can build web applications that are highly concurrent and can handle a large number of requests at the same time.

How WebAssembly Works with the Browser

When a Wasm module is loaded in a browser, it is executed by a virtual machine called the WebAssembly Runtime, which translates the Wasm code into machine code that the browser’s JavaScript engine can execute.

The WebAssembly Runtime is implemented in the browser as a JavaScript library and provides a set of APIs for loading, validating and executing Wasm modules. When a Wasm module is loaded, the Runtime validates the module’s bytecode and creates an instance of the module, which can be used to call its functions and access its data.

Wasm modules can interact with the browser’s Document Object Model (DOM) and other web APIs using JavaScript. For example, a Wasm module can modify the contents of a webpage, listen for user events, and make network requests using the browser’s web APIs.

One of the key benefits of using Wasm with the browser is that it provides a way to run code that is more performant than JavaScript. JavaScript is an interpreted language, which means that it can be slower than compiled languages like C++ or Go. However, by compiling code into Wasm format, it can be executed at near-native speeds, making it ideal for computationally intensive tasks such as machine learning or 3D graphics rendering.

Using WebAssembly with Go

The Go programming language has a compiler that can produce Wasm binaries, allowing Go programs to run in a web browser. The Go compiler for WebAssembly, called wasm, can be invoked using the GOARCH=wasm environment variable.

When compiling a Go program for WebAssembly, the Go compiler generates WebAssembly bytecode that can be executed in the browser using the WebAssembly Runtime. The generated Wasm module includes all of the Go runtime components needed to run the program, so no additional runtime support is required in the browser.

The Go compiler for WebAssembly supports the same set of language features as the regular Go compiler, including concurrency, garbage collection, and type safety. However, some Go features are not yet fully supported in WebAssembly, such as reflection and cgo.

Reflection. Reflection is a powerful feature in Go that allows programs to examine and manipulate their own types and values at runtime. However, due to the limitations of the Wasm runtime environment, reflection is not fully supported in Go programs compiled to WebAssembly. Some reflection capabilities may be limited or unavailable in WebAssembly binaries.

Cgo. The cgo tool in Go enables seamless integration with C code, allowing Go programs to call C functions and use C libraries. However, the cgo functionality is not currently supported in Go programs compiled to WebAssembly. This means that you cannot directly use cgo to interface with C code from WebAssembly binaries.

Technical Overview: How Wasm and Go Work Together

To compile Go code into WebAssembly format, you can use the Golang Wasm compiler. This tool generates a .wasm file that can be executed in a web browser. The compiler translates Go code into WebAssembly instructions that can be executed by a virtual machine in the browser.

Once you have the .wasm file, you need to load it into the browser using the WebAssembly JavaScript API. This API provides functions to load the module, instantiate it, and execute its functions.

You can load the .wasm file using the fetch() function, which loads the file as an ArrayBuffer. You can then instantiate the module using the WebAssembly.instantiate() function, which returns a Promise that resolves to a WebAssembly.Module object.

Calling Go Functions from JavaScript

After the WebAssembly module is loaded and instantiated, it exposes its functions to JavaScript. These functions can be called from JavaScript using the WebAssembly JavaScript API.

You can use the WebAssembly.instantiate() function to obtain a JavaScript object that contains the exported functions from the WebAssembly module. You can then call these functions from JavaScript just like any other JavaScript function.

Calling JavaScript Functions from Go

To call JavaScript functions from Go, you can use the syscall/js package. This package provides a way to interact with the JavaScript environment. You can create JavaScript values, call JavaScript functions, and handle JavaScript events from Go.

Use the js.Global() function to get the global object in the JavaScript environment. You can then call any function on this object using the Call() function, passing in the function name and any arguments.

The Golang WebAssembly API

The Golang WebAssembly API provides a set of functions that can be used to interact with WebAssembly modules from Go code running in a web browser. These functions allow Go programs to call functions defined in WebAssembly modules, pass values between Go and WebAssembly, and manipulate WebAssembly memory.

The Golang WebAssembly API is implemented as a set of Go packages, including “syscall/js,” which provides a bridge between Go and JavaScript, and “syscall/js/wasm,” which provides a bridge between Go and WebAssembly.

Using the Golang WebAssembly API, Go programs can load and instantiate Wasm modules, call functions defined in the modules, and manipulate the memory of the modules. For example, a Go program can load a Wasm module that performs complex computations, and then use the Golang WebAssembly API to call functions in the module and retrieve the results.

The Golang WebAssembly API also provides a way to define and export Go functions that can be called from WebAssembly modules. This allows Go programs to expose functionality to WebAssembly modules and provides a way to integrate Go code with existing JavaScript codebases.

Here’s a demonstration of how to compile a simple Go program to WebAssembly and load it in the browser

First, we need to install the Go compiler for WebAssembly. This can be done by running the following command:


This will install the WebAssembly-enabled version of the Go compiler.

Next, we can write a simple Go program that adds two numbers together:


We can then compile this program to WebAssembly by running the following command:


This will generate a WebAssembly binary file called “add.wasm.”

Now we can write some JavaScript code to load and execute the WebAssembly module. Here’s an example


This code creates a new instance of the Go WebAssembly API, loads the add.wasm module using the WebAssembly API, runs the module, and then calls the add function defined in the Go program.

Finally, we can load our JavaScript code in a webpage and view the output in the browser console. For example:


This HTML file loads the wasm_exec.js file, which is included with the Go compiler for WebAssembly, and then includes our JavaScript code to load and execute the add.wasm module.

That’s it! With these steps, we can compile a simple Go program to WebAssembly and load it in a web browser using JavaScript. This provides a powerful way to build high-performance web applications with the simplicity and ease of use of the Go programming language.

How to Use Go with Various Wasm Frameworks

Here’s an overview of different WebAssembly frameworks that can be used with Go, including AssemblyScript (a TypeScript-like language that compiles to Wasm) and TinyGo (a variant of Go that compiles to WebAssembly and other embedded systems).

AssemblyScript

AssemblyScript provides a familiar syntax for web developers and can be used alongside Go to provide additional functionality to a web application. Here’s an example of how to use Go with AssemblyScript:


In this example, we load the add.wasm module using the WebAssembly API and instantiate it with the Go import object. We then call the add function defined in the WebAssembly module and pass it two parameters. Finally, we start the Go runtime and call Go functions from JavaScript.

TinyGo

TinyGo provides a subset of the Go standard library and can be used to write low-level code that runs in the browser. Here’s an example of how to use TinyGo to call a function defined in a Go WebAssembly module:


In this example, we define a function called add that takes two integer parameters and returns their sum. We then use the “syscall/js” package to export this function to JavaScript. Finally, we block the main thread using a channel to prevent the Go program from exiting.

We can then call this function from JavaScript using the following code:


In this example, we instantiate the WebAssembly module and pass it to the Go runtime using the Go import object. We then run the Go program and call the add function defined in the Go program. The result is then printed to the console.

Using Wasm for Cross-Platform Development

WebAssembly code can be run in any environment that supports it, including browsers and standalone runtimes. Developers can use it to create applications that can run on multiple platforms with minimal code changes — fulfilling WebAssembly’s promise of “build once, run anywhere.” This can help to reduce development time and costs, while also providing a consistent user experience across different devices and platforms.

One way to use Wasm for cross-platform development is to build an application in a language that can be compiled to WebAssembly, such as Go or Rust. Once the application is built, it can be compiled to WebAssembly and deployed to the web, or compiled to native code and deployed to a desktop environment, using a framework like Electron or GTK.

Another way to use Wasm for cross-platform development is to build an application in a web-based language like JavaScript, and then compile it to WebAssembly using a tool like Emscripten. This approach can be especially useful for porting existing web applications to run on desktop environments, or for building applications that need to run on both the web and desktop.

Go programs can be compiled to both WebAssembly and native desktop environments using a number of different tools and frameworks.

For example, Electron is a popular framework for building cross-platform desktop applications using web technologies like HTML, CSS, and JavaScript. Go programs can be compiled to run on Electron using a tool like Go-Electron, which provides a way to package Go applications as Electron apps.

Another option is to use GTK, a popular cross-platform toolkit for building desktop applications. Go programs can be compiled to run on GTK using the gotk3 package, which provides Go bindings for GTK.

Group Created with Sketch.
TNS owner Insight Partners is an investor in: Pragma, fermyon, Docker.
THE NEW STACK UPDATE A newsletter digest of the week’s most important stories & analyses.