loading...
Cover image for Create frontend Go apps using go-web-app 🎉✨📦

Create frontend Go apps using go-web-app 🎉✨📦

talentlessguy profile image v 1 r t l ・4 min read

Some days ago I have written an article about writing frontend in Go.

Frontend development in Go and WebAssembly is very fun and quite easy to start with but inconvenient during continous app development. You have to type long commands, optimize bundle, write your own server, etc.

I have written a CLI that solves this problem. Let me introduce it, go-web-app.

Sounds cool, what is it?

go-web-app is a simple CLI for comfortable web development in Go. It has commands for creating a new app, building to WebAssembly and starting a development server. Later I'll add some more commands and features.

For building binaries it uses TinyGo.

For Go WASM support it uses TinyGo's wasm_exec.js file.

I wanna try it!

Before installing go-web-app you need to have TinyGo installed. Install here.

CLI is quite easy to install, just run the script:

curl https://raw.githubusercontent.com/talentlessguy/go-web-app/master/install.sh | bash

And try it:

gwa

It should output something like this:

NAME:
   go-web-app - Simple CLI for setting up Go WebAssembly frontend app.

USAGE:
   gwa [global options] command [command options] [arguments...]

VERSION:
   0.0.2

AUTHOR:
   v1rtl (twitter.com/v1rtl)

COMMANDS:
     init     Initialize a web app
     build    Compile Go to WebAssembly
     dev      Run a development server
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

As you can see, there are 3 main commands - init, build and dev. Let's start from init.

Create a new app

Simply type:

gwa init <app name>

and it will create a new app. Instead of <app name> enter your app's name, for example "app".

And you will see this output:

Great! Our project is located in app.

We need to go to our project, using cd:

cd app

App structure

Hm, what we see here? There is an src folder with Go files, empty build folder, JavaScript file and HTML file.

index.html

This file is an entry for loading WASM binaries. It contains some styles and, most importantly, WebAssembly loader.

WebAssembly.instantiateStreaming might not work in your browser if you use legacy, so better update it to latest version or use Chrome / Mozilla / Opera instead. However, I included a polyfill in case you don't want to update.

You can remove these styles in <style> tag if you don't need them.

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Go WebAssembly App</title>
        <style>
        body {
            margin: 0;
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            font-family: sans-serif
        }
        </style>
    </head>
    <body>
        <script src="wasm_exec.js"></script>
        <script>
            // Polyfill
            if (!WebAssembly.instantiateStreaming) {
                WebAssembly.instantiateStreaming = async (res, obj) => (
                    await WebAssembly.instantiate(await (await res).arrayBuffer(), obj)
                )
            }
            const go = new Go()
            WebAssembly.instantiateStreaming(fetch('/build/out.wasm'), go.importObject).then(result => {
                go.run(result.instance)
                WebAssembly.instantiate(result.module, go.importObject)
            })
        </script>
    </body>
    </html>

src

There are all the go files in src. If you put your code outside the directory it won't work. So better keep everything related to code in src.

After creating the app, we can see main.go file here. It is "Hello World" to ensure that everything works.

Here's how it looks like:

package main

import "syscall/js"

func main() {
    document := js.Global().Get("document")
    document.Get("body").Set("innerHTML", "<h1>Congrats!</h1><h2>You just created a new app using <code>go-web-app</code> 🎉</h2><a href='https://github.com/talentlessguy/go-web-app'>Star the project ⭐</a>")
}

We import "syscall/js" to access JavaScript environment, then set innerHTML property to that HTML code.

Equiualent in JS:

document.write('<h1>Congrats!</h1><h2>You just created a new app using <code>go-web-app</code> 🎉</h2><a href='https://github.com/talentlessguy/go-web-app'>Star the project ⭐</a>')

HTML Code here looks messy because I couldn't escape backtick symbol. This is how it should look:

<h1>Congrats!</h1>
<h2>You just created a new app using <code>go-web-app</code> 🎉</h2>
<a href='https://github.com/talentlessguy/go-web-app'>Star the project ⭐</a>

Now we need to compile our Go code.

Compile to WebAssembly

go-web-app uses TinyGo so WebAssembly output is super small and loads quite fast.

For building binaries we use gwa build. It takes all the go files from src and puts to build/out.wasm.

Type the command to see result:

gwa build

WebAssembly is available in build directory. It weights ~20Kb. You can check output size by yourself:

du -sh build

As you can see in CLI output, it says that we should start a development server. Let's do it.

Start the app

Dev server is basically a static file server that uses http.FileServer to serve files and also HTML.

To launch the server, type this command and pick a port you want. Otherwise, go-web-app will start on 8080.

gwa dev --port 80

Navigate to https://localhost, and you'll see this:

You don't need to open and close the server each time you build new binaries, server auto updates already. You only need to press Ctrl + R to reload the page.

Later, I'll maybe implement the mechanism of autoupdate using WebSockets.

To close the server, type Ctrl + C.

Conclusion

That's all. Please let me know if CLI is easy enough to use, what I should add / remove from it.

Also, you can support the project by hitting a star on GitHub.

Posted on by:

talentlessguy profile

v 1 r t l

@talentlessguy

16yo nullstack dev, OSSer ⚡, expert in nothing

Discussion

pic
Editor guide