Billy Chandler

Billy Chandler

1584001634

Build PWA with Go and WebAssembly

go-app is a package to build progressive web apps (PWA) with Go programming language and WebAssembly.

It uses a declarative syntax that allows creating and dealing with HTML elements only by using Go, and without writing any HTML markup.

The package also provides an http.handler ready to serve all the required resources to run Go-based progressive web apps.

Install

go-app requirements:

# Init go module (if not initialized):
go mod init

# Get package:
go get -u -v github.com/maxence-charriere/go-app/v6

How it works

app diagram

  • Users: The users of your app. They request pages and resources from their web browser.
  • app.Handler: An http.Handler used by your server or cloud function. It serves your app, its static resources, and all the required files to make it work on user browsers.
  • Application: Your app built with this package. It is built as a WebAssembly (.wasm) binary and is served by the app.Handler.
  • Other static resources: Styles, images, and scripts used by your app. They are also served by the app.Handler.

Declarative syntax

go-app uses a declarative syntax so you can write component-based UI elements just by using the Go programming language.

package main

import "github.com/maxence-charriere/go-app/v6/pkg/app"

type hello struct {
    app.Compo
    name string
}

func (h *hello) Render() app.UI {
    return app.Div().Body(
        app.Main().Body(
            app.H1().Body(
                app.Text("Hello, "),
                app.If(h.name != "",
                    app.Text(h.name),
                ).Else(
                    app.Text("World"),
                ),
            ),
            app.Input().
                Value(h.name).
                Placeholder("What is your name?").
                AutoFocus(true).
                OnChange(h.OnInputChange),
        ),
    )
}

func (h *hello) OnInputChange(src app.Value, e app.Event) {
    h.name = src.Get("value").String()
    h.Update()
}

func main() {
    app.Route("/", &hello{})
    app.Route("/hello", &hello{})
    app.Run()
}

The app is built with the Go build tool by specifying WebAssembly as architecture and javascript as operating system:

GOARCH=wasm GOOS=js go build -o app.wasm

Note that we named the build output app.wasm. The reason is that the HTTP handler requires the web assembly app to be named this way in order to be served.

HTTP handler

Once your app is built, the next step is to serve it.

This package provides an http.Handler implementation ready to serve your PWA and all the required resources to make it work in a web browser.

The handler can be used to create either a web server or a cloud function (AWS Lambda, GCloud function or Azure function).

package main

import (
    "net/http"

    "github.com/maxence-charriere/go-app/v6/pkg/app"
)

func main() {
    h := &app.Handler{
        Title:  "Hello Demo",
        Author: "Maxence Charriere",
    }

    if err := http.ListenAndServe(":7777", h); err != nil {
        panic(err)
    }
}

The server is built as a standard Go program:

go build

Note that you need to add app.wasm to the server location. The reason is that app.Handler is looking for a file named app.wasm in the server directory in order to serve the web assembly binary.

hello-local        # Server directory
├── app.wasm       # Wasm binary
├── hello-local    # Server binary
└── main.go        # Server code

Live apps

luck app hello app city app

#pwa #go #webassembly #wasm

What is GEEK

Buddha Community

Build PWA with Go and WebAssembly
Billy Chandler

Billy Chandler

1584001634

Build PWA with Go and WebAssembly

go-app is a package to build progressive web apps (PWA) with Go programming language and WebAssembly.

It uses a declarative syntax that allows creating and dealing with HTML elements only by using Go, and without writing any HTML markup.

The package also provides an http.handler ready to serve all the required resources to run Go-based progressive web apps.

Install

go-app requirements:

# Init go module (if not initialized):
go mod init

# Get package:
go get -u -v github.com/maxence-charriere/go-app/v6

How it works

app diagram

  • Users: The users of your app. They request pages and resources from their web browser.
  • app.Handler: An http.Handler used by your server or cloud function. It serves your app, its static resources, and all the required files to make it work on user browsers.
  • Application: Your app built with this package. It is built as a WebAssembly (.wasm) binary and is served by the app.Handler.
  • Other static resources: Styles, images, and scripts used by your app. They are also served by the app.Handler.

Declarative syntax

go-app uses a declarative syntax so you can write component-based UI elements just by using the Go programming language.

package main

import "github.com/maxence-charriere/go-app/v6/pkg/app"

type hello struct {
    app.Compo
    name string
}

func (h *hello) Render() app.UI {
    return app.Div().Body(
        app.Main().Body(
            app.H1().Body(
                app.Text("Hello, "),
                app.If(h.name != "",
                    app.Text(h.name),
                ).Else(
                    app.Text("World"),
                ),
            ),
            app.Input().
                Value(h.name).
                Placeholder("What is your name?").
                AutoFocus(true).
                OnChange(h.OnInputChange),
        ),
    )
}

func (h *hello) OnInputChange(src app.Value, e app.Event) {
    h.name = src.Get("value").String()
    h.Update()
}

func main() {
    app.Route("/", &hello{})
    app.Route("/hello", &hello{})
    app.Run()
}

The app is built with the Go build tool by specifying WebAssembly as architecture and javascript as operating system:

GOARCH=wasm GOOS=js go build -o app.wasm

Note that we named the build output app.wasm. The reason is that the HTTP handler requires the web assembly app to be named this way in order to be served.

HTTP handler

Once your app is built, the next step is to serve it.

This package provides an http.Handler implementation ready to serve your PWA and all the required resources to make it work in a web browser.

The handler can be used to create either a web server or a cloud function (AWS Lambda, GCloud function or Azure function).

package main

import (
    "net/http"

    "github.com/maxence-charriere/go-app/v6/pkg/app"
)

func main() {
    h := &app.Handler{
        Title:  "Hello Demo",
        Author: "Maxence Charriere",
    }

    if err := http.ListenAndServe(":7777", h); err != nil {
        panic(err)
    }
}

The server is built as a standard Go program:

go build

Note that you need to add app.wasm to the server location. The reason is that app.Handler is looking for a file named app.wasm in the server directory in order to serve the web assembly binary.

hello-local        # Server directory
├── app.wasm       # Wasm binary
├── hello-local    # Server binary
└── main.go        # Server code

Live apps

luck app hello app city app

#pwa #go #webassembly #wasm

Fannie  Zemlak

Fannie Zemlak

1599854400

What's new in the go 1.15

Go announced Go 1.15 version on 11 Aug 2020. Highlighted updates and features include Substantial improvements to the Go linker, Improved allocation for small objects at high core counts, X.509 CommonName deprecation, GOPROXY supports skipping proxies that return errors, New embedded tzdata package, Several Core Library improvements and more.

As Go promise for maintaining backward compatibility. After upgrading to the latest Go 1.15 version, almost all existing Golang applications or programs continue to compile and run as older Golang version.

#go #golang #go 1.15 #go features #go improvement #go package #go new features

Waylon  Bruen

Waylon Bruen

1649176940

Go-app: A Package to Build Progressive Web Apps with Go & WebAssembly

Go-app is a package for building progressive web apps (PWA) with the Go programming language (Golang) and WebAssembly (Wasm).

Shaping a UI is done by using a declarative syntax that creates and compose HTML elements only by using the Go programing language.

It uses Go HTTP standard model.

An app created with go-app can out of the box run in its own window, supports offline mode, and are SEO friendly.

Documentation (built with go-app)

go-app documentation

Install

go-app requirements:

go mod init
go get -u github.com/maxence-charriere/go-app/v9/pkg/app

Declarative syntax

Go-app uses a declarative syntax so you can write reusable component-based UI elements just by using the Go programming language.

Here is a Hello World component that takes an input and displays its value in its title:

type hello struct {
    app.Compo

    name string
}

func (h *hello) Render() app.UI {
    return app.Div().Body(
        app.H1().Body(
            app.Text("Hello, "),
            app.If(h.name != "",
                app.Text(h.name),
            ).Else(
                app.Text("World!"),
            ),
        ),
        app.P().Body(
            app.Input().
                Type("text").
                Value(h.name).
                Placeholder("What is your name?").
                AutoFocus(true).
                OnChange(h.ValueTo(&h.name)),
        ),
    )
}

Standard HTTP

Apps created with go-app complies with Go standard HTTP package interfaces.

func main() {
    // Components routing:
    app.Route("/", &hello{})
    app.Route("/hello", &hello{})
    app.RunWhenOnBrowser()

    // HTTP routing:
    http.Handle("/", &app.Handler{
        Name:        "Hello",
        Description: "An Hello World! example",
    })

    if err := http.ListenAndServe(":8000", nil); err != nil {
        log.Fatal(err)
    }
}

Getting started

Read the Getting Started document.

Built with go-app

Author: Maxence-charriere
Source Code: https://github.com/maxence-charriere/go-app 
License: MIT License

#go #golang #pwa #wasm 

Go-canvas: Library to Use HTML5 Canvas From Go-WASM

go-canvas

go-canvas is a pure go+webassembly Library for efficiently drawing on a html5 canvas element within the browser from go without requiring calls back to JS to utilise canvas drawing functions.

The library provides the following features:

  • Abstracts away the initial DOM interactions to setup the canvas.
  • Creates the shadow image frame, and graphical Context to draw on it.
  • Initializes basic font cache for text using truetype font.
  • Sets up and handles requestAnimationFrame callback from the browser.

Concept

go-canvas takes an alternate approach to the current common methods for using canvas, allowing all drawing primitives to be done totally with go code, without calling JS.

standard syscall way

In a standard WASM application for canvas, the go code must create a function that responds to requestAnimationFrame callbacks and renders the frame within that call. It interacts with the canvas drawing primitives via the syscall/js functions and context switches. i.e.

laserCtx.Call("beginPath")
laserCtx.Call("arc", gs.laserX, gs.laserY, gs.laserSize, 0, math.Pi*2, false)
laserCtx.Call("fill")
laserCtx.Call("closePath")

Downsides of this approach (for me at least), are messy JS calls which can't easily be checked at compile time, forcing a full redraw every frame, even if nothing changed on that canvas, or changes being much slower than the requested frame rate.

go native way

go-canvas allows all drawing to be done natively using Go by creating an entirely separate image buffer which is drawn to using a 2D drawing library. I'm currently using one from https://github.com/llgcode/draw2d which provides most of the standard canvas primitives and more. This shadow Image buffer can be updated at whatever rate the developer deems appropriate, which may very well be slower than the browsers animation rate.

This shadow Image buffer is then copied over to the browser canvas buffer during each requestAnimationFrame callback, at whatever rate the browser requests. The handling of the callback and copy is done automatically within the library.

Secondly, this also allows the option of drawing to the image buffer, outside of the requestAnimationFrame callback if required. After some testing it appears that it is still best to do the drawing within the requestAnimationFrame callback.

go-canvas provides several options to control all this, and take care of the browser/dom interactions

  • User specifies the go render/draw callback method when calling the START function. This callback passes the graphical context to the render routine.
  • Render routine can choose to return whether any drawing took place. If it returns false, then the requestAnimationFrame callback does nothing, just returns immediately, saving CPU cycles. (No point to copy buffers and redraw if nothing has changed) This allows the drawing to be adaptive to the rate of data changes.
  • The 'start' function accepts a maxFPS parameter. The library will automatically throttle the requestAnimationFrame callback to only do redraws or image buffer copies to this max rate. Note it MAY be slower depending on the Render time, and the requirements of the browser doing other work. When a tab is hidden, the browser regularly reduces and may even stop call to the animation callback. No critical timing should be done in the render/draw routings.
  • You may pass 'nil' for the render function. In this case all drawing happens totally under the users control, outside of the library. This may be more useful in future when WASM supports proper threading. Right now however, testing shows it is slower as all work is in the one thread, and you lose the scheduling benefits of the requestAnimationFrame call.

Drawing therefore, is pure go. i.e.

func Render(gc *draw2dimg.GraphicContext) bool {
    // {some movement code removed for clarity, see the demo code for full function}
    // draws red 🔴 laser
    gc.SetFillColor(color.RGBA{0xff, 0x00, 0x00, 0xff})
    gc.SetStrokeColor(color.RGBA{0xff, 0x00, 0x00, 0xff})

    gc.BeginPath()
    gc.ArcTo(gs.laserX, gs.laserY, gs.laserSize, gs.laserSize, 0, math.Pi*2)
    gc.FillStroke()
    gc.Close()
return true  // Yes, we drew something, copy it over to the browser

If you do want to render outside the animation loop, a simple way to cause the code to draw the frame on schedule, independent from the browsers callbacks, is to use time.Tick. An example is in the demo app below.

If however your image is only updated from user input or some network activity, then it would be straightforward to fire the redraw only when required from these inputs. This can be controlled within the Render function, by just returning FALSE at the start. Nothing is draw, nor copied (saving CPU time) and the previous frames data remains.

Known issues !

There is currently a likely race condition for long draw functions, where the requestAnimationFrame may get a partially completed image buffer. This is more likely the longer the user render operation takes. Currently think how best to handle this, ideally without locks. Turns out this is not an issue, due to the single threaded nature. Eventually if drawing is in a separate thread, this will have to be handled.

Demo

A simple demo can be found in: ./demo directory. This is a shameless rewrite of the 'Moving red Laser' demo by Martin Olsansky https://medium.freecodecamp.org/webassembly-with-golang-is-fun-b243c0e34f02

Compile with GOOS=js GOARCH=wasm go build -o main.wasm

Includes a Caddy configuration file to support WASM, so will serve by just running 'caddy' in the demo directory and opening browser to http://localhost:8080

Live

Live Demo available at: https://markfarnan.github.io/go-canvas

Future

This library was written after a weekend of investigation and posted on request for the folks on #webassembly on Gophers Slack.

I intend to extend it further, time permitting, into fully fledged support package for all things go-canvas-wasm related, using this image frame method.

Several of the ideas I'm considering are:

  •  Support for layered canvas, at least 3 for 'background', 'action' and 'user interaction'
  •  Traps & helper functions for mouse interactions over the canvas
  •  Unit tests - soon as I figure out how to do tests for WASM work.
  •  Performance improvements in the image buffer copy - https://github.com/agnivade/shimmer/blob/c073303a81ab9a90b6fc14eb6d90c3a1b930025e/load_image_cb.go#L40 has been suggested as a place to start.
  •  Detect if nothing has changed for the frame, and if so, don't even recopy the buffer, saving yet more time. May be useful for layers that change less frequently.
  •  Multiple draw / render frames to fix the 'incomplete image' problem. -- Not actually a problem
  •  Tidy up the close/end frame functionality to properly release resources on page unload and prevent 'browser reload errors' due to missing animation callback function.
  •  Update for Go 1.13 and Go Modules
  •  Add FPS Calculator metric

Others ? Feedback, suggestions etc. welcome. I can be found on Gophers Slack, #Webassembly channel.

Mark Farnan, February 2020

Author: Markfarnan
Source Code: https://github.com/markfarnan/go-canvas 
License: Apache-2.0 license

#go #golang #canvas #html5 #wasm 

Jake Whittaker

Jake Whittaker

1577384307

Go WebAssembly Tutorial - Building a Calculator Tutorial

In this article, we are going to be building a really simple calculator to give us an idea as to how we can write functions that can be exposed to the frontend, evaluate DOM elements and subsequently update any DOM elements with the results from any functions we call.

This will hopefully show you what it takes to write and compile your own Go-based programs for your frontend applications.

Introduction

So what does this really mean for Go and Web developers? Well, it gives us the ability to write our frontend web apps using the Go language and subsequently all its cool features such as its type safety

Now, this isn’t the first time we’ve seen the Go language being used for frontend purposes. GopherJS has been around for quite a while now and is pretty damn mature, however, the difference is that it compiles Go code to JS and not to WebAssembly.

A Simple Example

Let’s start off with a really simple example, this will simply output Hello World in the console whenever we click a button in our web page. Sounds exciting I know, but we can very quickly build this up into something more functional and cooler:

package main

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

Now, in order to compile this, you’ll have to set GOARCH=wasm and GOOS=js and you’ll also have to specify the name of your file using the -o flag like so:

$ GOARCH=wasm GOOS=js go build -o lib.wasm main.go

This command should compile our code into a lib.wasm file within our current working directory. We’ll be using the WebAssembly.instantiateStreaming() function to load this into our page within our index.html. Note - this code was stolen from the official Go language repo:

<!doctype html>
<!--
Copyright 2018 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>

<head>
	<meta charset="utf-8">
	<title>Go wasm</title>
</head>

<body>

	<script src="wasm_exec.js"></script>

	<script>
		if (!WebAssembly.instantiateStreaming) { // polyfill
			WebAssembly.instantiateStreaming = async (resp, importObject) => {
				const source = await (await resp).arrayBuffer();
				return await WebAssembly.instantiate(source, importObject);
			};
		}

		const go = new Go();
		
		let mod, inst;

		WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then((result) => {
			mod = result.module;
			inst = result.instance;
			document.getElementById("runButton").disabled = false;
		});

		async function run() {
			await go.run(inst);
			inst = await WebAssembly.instantiate(mod, go.importObject); // reset instance
		}

	</script>

	<button onClick="run();" id="myButton" disabled>Run</button>
</body>
</html>

We’ll also need the wasm_exec.js file which can be found here. Download that and save it alongside your index.html.

$ wget https://github.com/golang/go/blob/master/misc/wasm/wasm_exec.js

And, we also have a simple net/http based file server, again stolen from here, to serve up our index.html and our various other WebAssembly files:

package main

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

var (
	listen = flag.String("listen", ":8080", "listen address")
	dir    = flag.String("dir", ".", "directory to serve")
)

func main() {
	flag.Parse()
	log.Printf("listening on %q...", *listen)
	log.Fatal(http.ListenAndServe(*listen, http.FileServer(http.Dir(*dir))))
}

When you navigate to localhost:8080 once you’ve kicked off this server, you should see that the Run button is clickable and if you open up your console in the browser, you should see that it prints out Hello World every time you click the button!

Awesome, we’ve managed to successfully compile a really simple Go -> WebAssembly project and get it working in the browser.

A More Complex Example

Now for the good bit. Say, we wanted to create a more complex example that featured DOM manipulation, custom Go functions that could be bound to button clicks and more. Well thankfully, it’s not too difficult!

Registering Functions

We’ll start off by creating a few functions of our own that we want to expose to our frontend. I’m feeling rather unoriginal today so these are going to be just add and subtract.

These functions take in an array of type js.Value and use the js.Global().Set() function to set output to equal the result of any calculations done within our function. For good measure, we also print out to the console what the result is as well:

func add(i []js.Value) {
	js.Global().Set("output", js.ValueOf(i[0].Int()+i[1].Int()))
	println(js.ValueOf(i[0].Int() + i[1].Int()).String())
}

func subtract(i []js.Value) {
	js.Global().Set("output", js.ValueOf(i[0].Int()-i[1].Int()))
	println(js.ValueOf(i[0].Int() - i[1].Int()).String())
}

func registerCallbacks() {
	js.Global().Set("add", js.NewCallback(add))
	js.Global().Set("subtract", js.NewCallback(subtract))
}

func main() {
	c := make(chan struct{}, 0)

	println("WASM Go Initialized")
	// register functions
	registerCallbacks()
	<-c
}

You’ll notice that we’ve modified our main function slightly by calling make and creating a new channel. This effectively turns our previously short-lived program into a long-running one. We also call another function registerCallbacks() that acts almost like a router, but instead creates new Callbacks that effectively bind our newly created functions to our frontend.

In order for this to work, we have to very slightly modify the JavaScript code within our index.html to run our program instance as soon as it’s fetched it:

const go = new Go();
let mod, inst;
WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(async (result) => {
	mod = result.module;
	inst = result.instance;
	await go.run(inst)
});

Load this up in your browser once again and you should see that, without any button presses, WASM Go Initialized prints out in the console. This means that everything has worked.

We can then start calling out to these functions from the likes of <button> elements like so:

<button onClick="add(2,3);" id="addButton">Add</button>
<button onClick="subtract(10,3);" id="subtractButton">Subtract</button>

Remove the existing Run button and add these two new buttons to your index.html. When you reload the page in the browser and open up the console, you should be able to see the outputs of this function printing out.

We are slowly but surely starting to get somewhere with this!

Evaluating DOM Elements

So, I guess the next stage, is to start evaluating DOM elements and using their values instead of hard-coded values.

Let’s modify the add() function so that I can pass in 2 ids of <input/> elements and then add the values of these elements like so:

func add(i []js.Value) {
	value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()
	value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()
	js.Global().Set("output", value1+value2)
	println(value1 + value2)
}

We can then update our index.html to have the following code:

<input type="text" id="value1"/>
<input type="text" id="value2"/>

<button onClick="add('value1', 'value2');" id="addButton">Add</button>

If you enter some numeric values into both our inputs and then click the Add button, you should hopefully see a concatenation of the two values print out in the console.

What have we forgotten? We need to parse these string values as int values:

func add(i []js.Value) {
	value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()
	value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()

	int1, _ := strconv.Atoi(value1)
	int2, _ := strconv.Atoi(value2)

	js.Global().Set("output", int1+int2)
	println(int1 + int2)
}

You’ll probably notice that I’m not handling errors here as I’m feeling lazy, and this is just for show.

Try recompiling this code now and reloading your browser, you should notice that if we enter the values 22 and 3 in both our inputs, it successfully outputs 25 in the console.

Manipulating DOM elements

Our calculator wouldn’t be very good if it didn’t actually report the results within our page, so let’s fix that now by taking in a third id that we’ll output the results to:

func add(i []js.Value) {
	value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()
	value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()

	int1, _ := strconv.Atoi(value1)
	int2, _ := strconv.Atoi(value2)

	js.Global().Get("document").Call("getElementById", i[2].String()).Set("value", int1+int2)
}

Finally, let’s update our subtract method:

func subtract(i []js.Value) {
	value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()
	value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()

	int1, _ := strconv.Atoi(value1)
	int2, _ := strconv.Atoi(value2)

	js.Global().Get("document").Call("getElementById", i[2].String()).Set("value", int1-int2)
}

Our finished index.html should look something like this:

<!doctype html>
<!--
Copyright 2018 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>

<head>
	<meta charset="utf-8">
	<title>Go wasm</title>
</head>

<body>

	<script src="wasm_exec.js"></script>

	<script>
		if (!WebAssembly.instantiateStreaming) { // polyfill
			WebAssembly.instantiateStreaming = async (resp, importObject) => {
				const source = await (await resp).arrayBuffer();
				return await WebAssembly.instantiate(source, importObject);
			};
		}

		const go = new Go();
		let mod, inst;
		WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(async (result) => {
			mod = result.module;
			inst = result.instance;
			await go.run(inst)
		});

	</script>

	<input type="text" id="value1"/>
	<input type="text" id="value2"/>

	<button onClick="add('value1', 'value2', 'result');" id="addButton">Add</button>
	<button onClick="subtract('value1', 'value2', 'result');" id="subtractButton">Subtract</button>

	<input type="text" id="result">

</body>

</html>

Conclusion

So, in this tutorial, we managed to learn how we can compile our Go programs into WebAssembly using the new v1.11 of the Go language. We created a really simple calculator that exposes functions from our Go code to our frontend and also does a bit of DOM parsing and manipulation to boot.

Hopefully, you found this article useful/interesting! If you did, then I’d love to hear from you in the comments section below.

#WebAssembly #Go #WebDev