(Tiny)Go to WebAssembly
Tags: go, tutorial, webassembly
Published: 2019-07-05 22:22:24

[Gophers](https://www.google.com/search?q=gopher+golang&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjO3LCmj6DjAhVOZ1AKHdVaALYQ_AUIECgB&biw=1920&bih=948) not only look cute but also they are powerful.

![](https://thepracticaldev.s3.amazonaws.com/i/1eaxlpr98hv1bedjgyhg.gif)

I :heart: [statically typed languages](https://en.wikipedia.org/wiki/Type_system) and [Golang](https://golang.org/) is statically typed too. 

 > Golang is syntactically similar to C, but with memory safety, Garbage Collection and CSP-style concurrency. - [Wikipedia](https://en.wikipedia.org/wiki/Go_(programming_language))

We can compile Go into [WebAssembly](https://webassembly.org/). This means we can write channels in Golang and run them on the browser.

WebAssembly in Golang is still in its early days. :unicorn:

Golang is very simple to write. Thus it is easy to compile the existing application straight into WebAssembly modules provided they don't have any file path or system level features which will not be available for WebAssembly during its runtime.

# Hello World

Create a folder called `go-wasm` with child folders `out` and `go`;

```
 go-wasm/
 |__ out/
 |__ go/
```

Create a file called `main.go` inside the `go` folder and enter the following contents:

 ```go
package main

func main() {
    println("Hello World!!!")
}
```

Run the go file with `go run go/main.go`. This will print `Hello World`. Ain't that easy. 

Now we can compile this into WebAssembly module and run as a WebAssembly. 

```bash
GOOS=js GOARCH=wasm go build -o out/main.wasm go/main.go
```

This will generate the `main.wasm` inside the `out` folder. Unlike Rust, Golang does not generate any binding file. We can use the binding file available from the TinyGo's official repository [here](https://github.com/tinygo-org/tinygo/blob/master/targets/wasm_exec.js).

Download the file and move it inside the `out` directory. 

Create an `index.html` file inside the `out` directory and add the following contents:

```html
<!doctype html>
<html>
        <head>
                <meta charset="utf-8">
                <title>Go wasm</title>
        </head>

        <body>
                <script src="wasm_exec.js"></script>
                <script>
                        const go = new Go();
                        WebAssembly.instantiateStreaming(fetch('main.wasm'),go.importObject).then( res=> {
                                go.run(res.instance)	
                        })
                </script>

        </body>
</html>

```

The `index.html` loads the `wasm_exec.js` file. Note that this file works for both Browser and NodeJS environment. It exports a `Go` object.

Then we add a local script. Inside the script we do the following:

* Instantiate `Go` from the `wasm_exec.js`.
* Fetch the WebAssembly Module using [instantiateStreaming](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming)

Run the local server from the folder to see the `Hello World`. 

But wait, we are writing Golang. Golang makes it fairly easy to write a simple WebServer in Golang. Let us write one. 

Create a file called `webServer.go` in the root directory with the following contents.

```go
package main

import (
        "log"
        "net/http"
        "strings"
)

const dir = "./out"

func main() {
        fs := http.FileServer(http.Dir(dir))
        log.Print("Serving " + dir + " on http://localhost:8080")
        http.ListenAndServe(":8080", http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
                resp.Header().Add("Cache-Control", "no-cache")
                if strings.HasSuffix(req.URL.Path, ".wasm") {
                        resp.Header().Set("content-type", "application/wasm")
                }
                fs.ServeHTTP(resp, req)
        }))
}
```

This serves the files inside the `out` folder. Now run the server using `go run webServer.go`. :tada: Isn't that easy?

Head over to the `http://localhost:8080` and open the console to see the awesome `Hello World`.

The directory structure should look like below.

```
├── go
│   └── main.go
└── out
    ├── index.html
    ├── wasm_exec.js
    └── main.wasm
```

It is very important to note the file sizes of the generated WebAssembly module. And it is whooping 1.3MB for just a Hello World. That is huge right. 

```
-rw-r--r--  1 sendilkumar  staff   482B Jul  5 23:20 index.html
-rwxr-xr-x  1 sendilkumar  staff   1.3M Jul  5 23:19 main.wasm
-rw-r--r--  1 sendilkumar  staff    13K Jul  5 23:18 wasm_exec.js
```

Any performance WebAssembly might give, it is not desirable to have it if the modules are huge.

Don't worry we have Teeny TinyGO.

# Tiny Go

![](https://thepracticaldev.s3.amazonaws.com/i/2fz3lq3kohgoltymt7zq.png)

The TinyGo is a project built to take Golang into microcontrollers and modern web browsers. They have a brand new compiler that compiles based on LLVM. With TinyGo we can generate teeny tiny libraries that are optimized to execute in the chips.

Check out how to install TinyGo [here](https://tinygo.org/getting-started/).

Once installed, you can use TinyGo to compile any Golang code. We can compile Golang into WebAssembly module using the following command.

```
tinygo build -o out/main.wasm -target wasm ./go/main.go
```

Now go to the browser and refresh the page to see `Hello World` still printed. 

The most important thing is the generated WebAssembly module is just 3.8K :tada: :tada: :tada:

```
-rw-r--r--  1 sendilkumar  staff   482B Jul  5 23:20 index.html
-rwxr-xr-x  1 sendilkumar  staff   3.8K Jul  5 23:29 main.wasm
-rw-r--r--  1 sendilkumar  staff    13K Jul  5 23:18 wasm_exec.js
```

Since we have LLVM underneath we can tweak it further using the `-opt` flag. The maximum size optimization is obtained with the -opt=z flag and `TinyGo` uses this by default. Because those tiny devices have limited memory.

Keep tuning in the next post, let us re-create the classic Dev's offline page using TinyGo and WebAssembly.


![](https://thepracticaldev.s3.amazonaws.com/i/18dmdedoviqs1vrrjqoo.png)

I hope this gives you a motivation to start your awesome WebAssembly journey. If you have any questions/suggestions/feel that I missed something feel free to add a comment.

You can follow me on [Twitter](https://twitter.com/sendilkumarn).

If you like this article, please leave a like or a comment. :heart: