Getting started with WebAssembly using Go

Getting started with WebAssembly using Go

This WebAssembly and Go tutorial explains how to get started with WebAssembly and Go. Curious about WebAssembly and how we can use WebAssembly using Go? Introduces the Go WebAssembly compilation target, shows what is possible today and discusses what will be possible tomorrow.

Curious about WebAssembly and how we can use it with Go? In this session, Johan introduces the technology, shows how to get started with WebAssembly and Go, discusses what is possible today and what will be possible tomorrow.

What is WebAssembly?

WebAssembly is a web standard binary instruction format. It's developed by the W3C and it grew out of the asm.js and Google's Native Client projects. It aims to provide portable targets to allow code to be compiled once and run across many platforms. Currently runtimes for WASM include:

  • Browsers: Chrome, Firefox, Safari, Edge and others since late 2017
  • Native runtimes: wasmer, wasmtime, wagon, life, lucent, WAVM, more

Many of these runtimes have appeared fairly recently, meaning that WebAssembly is no longer just a runtime for the browser but can be used for code that can run anywhere, including bare metal.

WebAssembly in Go

As of Go 1.13, there is experimental support for WebAssembly using the JavaScript interface but as it is only experimental, using it in production is not recommended. Support for the WASI interface is not currently available but has been planned and may be available as early as Go 1.14.

It's quite easy to get started with WebAssembly in Go. Let's start with a simple "Hello World". The following code will allow us to compile a Go program that can be loaded in a browser. Note the build tag at the top.

// +build js,wasm

package main

import "fmt"

func main() {
	fmt.Println("Hello World")
}

We then compile the program specifying the wasm architecture and js GOOS environment variables. Additionally to get the setup up and running, we'll need to copy some files that will load the binary into the browser and execute it.

GOOS=js GOARCH=wasm go build -o ./html/test.wasm ./hello/main.go
cp $(go env GOROOT)/misc/wasm/wasm_exec.html ./html/index.html // Example of how to load WebAssembly
cp $(go env GOROOT)/misc/wasm/wasm_exec.js ./html/wasm_exec.js // Mandatory

Lastly, we'll need a webserver to ensure the right content type is served.

var contentTypeSetter = func(h http.Handler) http.Handler {
    return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
        if strings.HasSuffix(req.URL.Path, ".wasm") {
            resp.Header().Set("content-type", "application/wasm")
        }
        h.ServeHTTP(resp, req)
    })
}

The examples in Johan's repo has some nice Makefile targets to simplify the process, as well as many other examples and a webserver that's ready to use. Once the server is up and running, launch a browser and bring up the console to see the message being printed out. By default, standard output will go to the console.

If you look at the size of the file, you can start seeing some of the challenges. This is a very large file for a simple "Hello World".

JavaScript interface

The next example in the tutorial makes use of the JavaScript interface syscall/js, based on the GopherJS interface. An important thing to note is that any data that is passed to JavaScript must be copied as there is no shared memory yet. Data transfers should be minimized for greater performance. The following code writes an element to the DOM instead of the console. The file size of this binary is "only 1.37MB", as we're no longer importing the fmt package. Large packages compile to much larger binaries, something to be conscious of when building for WASM.

package main

import "syscall/js"

func setDemo() {
    doc := js.Global().Get("document")
    d := doc.Call("getElementById", "demo")
    d.Set("innerHTML", "Hello <b>Go!</b>")
}

net/http client

It's possible to use some of the standard libraries in WebAssembly, including the net/http library, which is built on top of the browser's Fetch API. The next example shows us how to do just that by making a request and printing its output to the DOM.

...
var document js.Value

func init() {
	document = js.Global().Get("document")
}

type writer js.Value

// Write implements io.Writer.
func (d writer) Write(p []byte) (n int, err error) {
	node := document.Call("createElement", "div")
	node.Set("textContent", string(p))
	js.Value(d).Call("appendChild", node)
	return len(p), nil
}

func main() {
	t := document.Call("getElementById", "target")
	logger := log.New((*writer)(&t), "", log.LstdFlags)

	c := http.Client{}
	req, err := http.NewRequest(
		"POST",
		"https://httpbin.org/anything",
		strings.NewReader(`{"test":"test"}`),
	)
  ...
 	logger.Print(string(b))
}

Go test

You might think it would be hard to run tests, but there are already a couple of options for WebAssempbly test runners. The standard library has go_wasm_js_exec for node and wasmbrowser supports testing the code using the browser.

Web frameworks

Vecty

The first web framework example shown is using vecty which is very React-like. It was originally written for GopherJS and was later modified to support WebAssembly. Set the title of the window and specify the function to render which defines how the struct should be rendered in a browser. Syntax much like inline html that react uses, but with the power of Go. This is really powerful and expressive.

package main

import (
	"github.com/gopherjs/vecty"
	"github.com/gopherjs/vecty/elem"
	"github.com/gopherjs/vecty/event"
	"github.com/microcosm-cc/bluemonday"
	"github.com/slimsag/blackfriday"
)

func main() {
	vecty.SetTitle("Markdown Demo")
	vecty.RenderBody(&PageView{
		Input: `# Markdown Example

This is a live editor, try editing the Markdown on the right of the page.
`,
	})
}
...
// Render implements the vecty.Component interface.
func (p *PageView) Render() vecty.ComponentOrHTML {
	return elem.Body(
		// Display a textarea on the right-hand side of the page.
		elem.Div(
			vecty.Markup(
				vecty.Style("float", "right"),
			),
			elem.TextArea(
				vecty.Markup(
					vecty.Style("font-family", "monospace"),
					vecty.Property("rows", 14),
					vecty.Property("cols", 70),

					// When input is typed into the textarea, update the local
					// component state and rerender.
					event.Input(func(e *vecty.Event) {
						p.Input = e.Target.Get("value").String()
						vecty.Rerender(p)
					}),
				),
				vecty.Text(p.Input), // initial textarea text.
			),
		),

		// Render the markdown.
		&Markdown{Input: p.Input},
	)
}
...

Vugu

The last example shown is Vugu. It is a Vue-like library and uses a relatively new custom file format, which is a super set of html with code generators. Vugu provides a generator vugugen which takes .vugu files and generates the Go code, which you should never have to modify. For handling asynchronous functions, goroutines are used, and Vugu offers locking functions Lock and UnlockRender. The embedded code is Go.

<div class="demo-comp">
	<div vg-if='data.isLoading'>Loading...</div>
	<div vg-if='len(data.bpi.BPI) > 0'>
		<div>Updated: <span vg-html='data.bpi.Time.Updated'></span></div>
		<ul>
			<li vg-for='data.bpi.BPI'>
				<span vg-html='key'></span> <span vg-html='fmt.Sprint(value.Symbol, value.RateFloat)'></span>
			</li>
		</ul>
	</div>
	<button @click="data.HandleClick(event)">Fetch Bitcoin Price Index</button>
</div>

You can try it in the playground https://play.vugu.org.

Challenges

We've seen a few demos but what about the file sizes? An easy solution to reducing the size of the files is to use compression like gzip. The demo webserver in the repo has support for gzipping content via a command line flag, which when demo'd, reduced the size of the content being served by roughly 75%.

go run main.go --gzip

Another option would be to use a Content Delivery Network (CDN), to distribute the content closer to the users and provide compression. The wasmgo project can be used to deploy binaries to CDNs easily.

TinyGo

It's still very early days, but a very exciting project to bring Go to microcontrollers. Tinygo is built on a completely different compiler stack, different runtime with its own garbage collector. It doesn't have a standard implementation for some libraries like http for example, but it does support WebAssembly. The example available in the repo uses a Docker container to run tiny locally and reduced the size of the binary created from 2.58MB down to 33.40KB.

make tinygo-canvas
go run main.go
Looking ahead

Though it's currently usable, there are still many areas where work needs to be done for WebAssembly in Go. Some areas of improvement include:

  • removing the need to copy when using the APIs
  • adding support for threading
  • reduce the size of the binaries being compiled, could be much smaller if we didnt have to compile the garbage collector
  • providing typesafe APIs, gowebapi is in the works
  • support for WASI
Conclusion

WebAssembly in Go is here and ready to try! Although the landscape is evolving really quickly, the opportunity is huge. The ability to deliver truly portable system binaries could potentially replace JavaScript in the browser. WebAssembly has the potential to finally realize the goal of being platform agnostic without having to rely on a JVM.

Hire Dedicated eCommerce Web Developers | Top eCommerce Web Designers

Hire Dedicated eCommerce Web Developers | Top eCommerce Web Designers

Build your eCommerce project by hiring our expert eCommerce Website developers. Our Dedicated Web Designers develop powerful & robust website in a short span of time.

Build your eCommerce project by hiring our expert eCommerce Website developers. Our Dedicated Web Designers develop powerful & robust website in a short span of time.

Hire Now: https://bit.ly/394wdOx

Mobile App Development Company India | Ecommerce Web Development Company India

Mobile App Development Company India | Ecommerce Web Development Company India

Best Mobile App Development Company India, WebClues Global is one of the leading web and mobile app development company. Our team offers complete IT solutions including Cross-Platform App Development, CMS & E-Commerce, and UI/UX Design.

We are custom eCommerce Development Company working with all types of industry verticals and providing them end-to-end solutions for their eCommerce store development.

Know more about Top E-Commerce Web Development Company

Building full-stack web apps with Go, Vecty and WebAssembly

Building full-stack web apps with Go, Vecty and WebAssembly

In this article, you'll learn how to build full-stack web apps with Go, Vecty and WebAssembly

Many of us have heard of — and maybe written — full-stack web applications. We do them in a variety of different ways, but the common denominator is usually JavaScript and Node.js.

Today, we’re going to break with that tradition and write a complete web applicationfront end and backend – without writing a line of JavaScript. We’ll be comparing the developer experience to JavaScript along the way, but we’re going to be only writing Go for this entire project.

We’ll learn how to build a single page link shortener application with just Go, and we’ll end up with working code that shows it in action.

Prerequisites

Today, we’re going to be focusing on Go so make sure you’ve installed the tooling on your machine. I’m going to assume you have basic knowledge of Go, but check out the free Tour of Go to brush up (or learn!) if you need to.

All the shell commands that I’m going to be showing work on a Mac, but should also work on most Linux systems (including WSL!).

Finally, make sure to clone the repository with the code for this article.

And then you’re good to go, let’s get started!

Getting started

First, we’re going to get the application running locally.

Coming from Webpack and surrounding technologies — which you’d use to build a web app with JavaScript — building and running this application is embarrassingly easy. There’s a front-end and a backend part (more on that below), and you compile both of them with the go tool, which requires no configuration.

First, run the backend server:

$ go run .

Next, build the front end in a new terminal window:

$ cd frontend
$ GOOS=js GOARCH=wasm go build -o ../public/frontend.wasm

Finally, go to https://localhost:8081 in your browser to see the app in action.

How this all works

Like most web apps, our link shortener has a front-end and backend piece. In our app, the backend is just a static server written in Go. All of the magic is in the front-end directory, so let’s start there!

If you’re familiar with React or the DOM, you’ll recognize a lot of the concepts we’ll cover. If not, this stuff will come naturally.

We’re using a new Go framework called Vecty to organize our application. Vecty forces you to break down your app into components and arrange them into a tree. The whole scheme is really similar to HTML and the DOM or React.

Here’s what our app’s high-level components would look like if they were HTML:

  • A h2 for the title of the page
  • A form to enter the link to shorten
  • A div to hold the shortened link (this value is dynamically updated as the user types the link into the above)
  • An a to save the short link

Vecty components are so similar to React that they look like the Go equivalent of JSX, except that they have more parentheses.

Let’s zoom in on one and see how it works. Here’s the code for the form component:

elem.Form(
    elem.Input(vecty.Markup(
        event.Input(func(e *vecty.Event) {
            short := uuid.NewV4().String()[0:5]
            h.shortened = short
            vecty.Rerender(h)
        }),
    )),
)

First, elem.Form and elem.Input on lines 1 and 2 are for the <form> and <input> tags, respectively. Those are both Go functions that take one or more arguments. Each argument is something that goes between the opening and closing HTML tags. For example, the stuff we pass to elem.Form goes in between <form> and </form>. This is what the above Go code would look like in HTML:

<form>
    <input>
    </input>
</form>

Pretty simple, right?

The last piece of code we didn’t look at is that event.Input function. This is an event handler just like in HTML/JavaScript. This function takes in another function, which in this case is roughly an onchange handler. Just like you’d expect, that *vecty.Event argument the handler takes in is roughly the same as the JavaScript event.

The logic to actually shorten the link is all inside this handler, and it’s fairly simple. Here is that code commented thoroughly:

// First, make a new UUID and take the first 5 characters of it.
// This will be our new shortcode
short := uuid.NewV4().String()[0:5]
// Next, write the shortcode to a variable. This variable is shared
// with the <div>, so when we re-render this component, the <div> will
// get updated
h.shortened = short
// Finally, re-render the component so that the <div> gets the new shortcode.
// Unlike React, there's no automatic diff functionality. We tell Vecty
// explicitly which components to re-render.
vecty.Rerender(h)
You get web assembly for free

Vecty can scale to big applications because of this component structure, and we can scale our app as big as we want by adding more components as needed. For example, we can add a component above our current top-level to dynamically route to different sub-components based on the URL. This would be similar to some of the popular react-router implementations.

One final thing to keep in mind is that WASM is not HTML, it’s a full departure from the DOM and everything HTML.

I compared all the components in the last section to HTML tags, but they aren’t! That’s where the big difference between Vecty / WASM and React comes in. We’re compiling our Go code straight to WASM, which represents these components differently from the DOM.

Conclusion

At the end of the day, you get some big benefits from using Go and Vecty to build apps:

  1. You get to think in terms of components and nesting, just like with React and the DOM
  2. You can write as much dynamic logic as you want, right next to your components, all in pure Go
  3. You can share code between the server and client, similar to writing a React client and a Node.js server
  4. You get to take advantage of WASM
  5. Or you can compile your Vecty code to HTML too if you want! That’s a whole other article

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading about WebAssembly

WebAssembly: The Future of JS and a Multi-Language Web

Using WebAssembly With Node.js

Get started with WebAssembly using JavaScript

WebAssembly for Web Developers

What is WebAssembly?

Speed, Speed, Speed: JavaScript vs C++ vs WebAssembly

WebAssembly Disrupting JavaScript

WebAssembly: Expectation vs. Reality