Go and GopherJS

18 February 2015

Dmitri Shuralyov

Software Engineer, Triggit

Overview

Go

Motivation

(From mmcgrana.github.io/2012/09/getting-started-with-go-on-heroku.html.)

Good for writing general code

Use packages to abstract out platform-specific implementation details:

Use general interfaces that can be implemented and provided:

type FileSystem interface {
    Opener
    Lstat(path string) (os.FileInfo, error)
    Stat(path string) (os.FileInfo, error)
    ReadDir(path string) ([]os.FileInfo, error)
    String() string
}

Go target platforms

GopherJS

GopherJS GitHub Repo

What is supported?

Demo.

Easy to get started.

$ go get -u github.com/gopherjs/gopherjs

$ gopherjs build

Reasons to use Go in frontend

Packages that can be compiled to JavaScript

go/parser and go/printer

func process(input string) string {
    // Parse the AST.
    fset := token.NewFileSet()
    fileAst, parseErr := parser.ParseFile(fset, "", input, parser.ParseComments|parser.AllErrors)

    // Print the AST.
    var config = &printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
    var buf bytes.Buffer
    err := config.Fprint(&buf, fset, fileAst)
    if err != nil {
        panic(err)
    }

    // Append parsing errors, if any.
    if parseErr != nil {
        buf.WriteString("\n---\n" + parseErr.Error())
    }

    return buf.String()
}

Packages that can be compiled to JavaScript

github.com/russross/blackfriday
github.com/microcosm-cc/bluemonday
github.com/sourcegraph/syntaxhighlight
github.com/shurcooL/go/highlight_go
github.com/shurcooL/go/highlight_diff
go/format
github.com/shurcooL/markdownfmt/markdown

Packages that can be compiled to JavaScript

Achieving all that in the browser took minutes, because existing Go code could be reused:

import "github.com/shurcooL/go/github_flavored_markdown"

func run(event dom.Event) {
    output.SetInnerHTML(string(github_flavored_markdown.Markdown([]byte(input.Value))))
}

func main() {
    input.AddEventListener("input", false, run)
    input.Value = initial
    input.SelectionStart, input.SelectionEnd = len(initial), len(initial)
    run(nil)
}

Running Go code in the browser?

Running Go code in the browser?

APIs in the browser

APIs in the browser

GopherJS and JavaScript

godoc.org/github.com/gopherjs/gopherjs/js

Accessing native JavaScript APIs in Go code:

// document.write("Hello world!");

js.Global.Get("document").Call("write", "Hello world!")

Providing Go functionality to other JavaScript code:

someGoFunc := func() {
    ...
}
js.Global.Set("SomeFunction", someGoFunc)

Type conversions between Go types and JavaScript types

godoc.org/github.com/gopherjs/gopherjs/js

APIs in the browser

APIs in the browser

Source: github.com/gopherjs/gopherjs/wiki/bindings

APIs in the browser

Bindings to JS libraries

Go Wrappers

GopherJS Issue Resolution Times

"Wow, awesome 1 hour fix, that was fast! Thanks!"

"Wow, that was fast - thank you very much for your efforts! :)"

"Great work! Thank you!"

"Thanks for your prompt replies!"

14 hours to fix a compiler bug.

GopherJS GitHub Repo

github.com/shurcooL/play/95

Minor change of topic...

Demo.

View Source: gotools.org/github.com/shurcooL/play/95

(Also github.com/shurcooL/play/97 and github.com/shurcooL/Hover.)

Other Demos

Compile Errors

Compile Errors

output, err := markdown.Process("", 12345, nil)
if err != nil {
    panic(err)
}

Compile Errors

var _ io.Reader = markdownRenderer{}

Debugging

Debugging

Debugging

Debugging

Debugging

Debugging

Debugging

Performance

Performance

Performance

Performance

Size of generated code

Limitations

Limitations

Limitations

Limitations

Advantages

Takeaway

Which language you use in the frontend is a choice you have to make.

Something fun to try at home

Community

Thank you

Dmitri Shuralyov
Software Engineer, Triggit
shurcooL@gmail.com
https://github.com/shurcooL
@shurcooL

Extras

Packages that can be compiled to JavaScript

go/parser and go/printer

package main

import ("bytes"; "go/parser"; "go/printer"; "go/token"; "honnef.co/go/js/dom")

var document = dom.GetWindow().Document()

var input = document.GetElementByID("input").(*dom.HTMLTextAreaElement)
var output = document.GetElementByID("output").(dom.HTMLElement)

var initial = "package main\n\n..."

func run(_ dom.Event) {
    output.SetTextContent(process(input.Value))
}

func main() {
    input.AddEventListener("input", false, run)
    input.Value = initial
    input.SelectionStart, input.SelectionEnd = 153, 153
    run(nil)
}

Code Samples

shareIcon := document.GetElementByID("share-icon")
shareIcon.AddEventListener("click", false, func(event dom.Event) {
    event.PreventDefault()
    fmt.Println("clicked!")
})

Setting CSS style of an element.

shareIcon.Style().SetProperty("display", "none", "")

Thank you

Dmitri Shuralyov

Software Engineer, Triggit

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)