GopherJS

at Helsinki Gophers meetup

11 May 2016

Timo Savola

CTO, Ninchat

Go & Me

GopherJS

go get github.com/gopherjs/gopherjs
gopherjs build

Standard packages

Fully supported: 110

Partially supported: 12

Not supported: 21

Goroutines are supported

Access the JavaScript world

package main

import "github.com/gopherjs/gopherjs/js"

var doc = js.Global.Get("document")

func main() {
    div := doc.Call("createElement", "div")
    div.Set("innerText", "hello world")

    doc.Get("body").Call("appendChild", div)
}

Export objects to the JavaScript world, part 1

const MyString = "hello world"

func MyApplyFunc(callable *js.Object, arg string) {
    if callable != js.Undefined {
        callable.Invoke(arg)
    }
}

func main() {
    js.Global.Get("window").Set("MyStuff", map[string]interface{}{
        "MY_STRING":   MyString,
        "myApplyFunc": MyApplyFunc,
    })
}

> MyStuff.myApplyFunc(someUnaryFunction, "asdf")

Export objects to the JavaScript world, part 2

type ValueThing struct {
    Foo int
    Bar string
    Baz []uint16
}

func NewValueThing() *ValueThing {
    return &ValueThing{}
}

func (t *ValueThing) GetSomething() int {
    return 42
}

> t = examples.NewValueThing()
> t
Object {Foo: 0, Bar: "", Baz: Array[0]}
> t.GetSomething()
Uncaught TypeError: t.GetSomething is not a function

Export objects to the JavaScript world, part 3

type ActiveThing struct {
    Foo int
    Bar string
    Baz []uint16
}

func NewActiveThing() *js.Object {
    return js.MakeWrapper(&ActiveThing{})
}

func (t *ActiveThing) GetSomething() int {
    return 42
}

> t = examples.NewActiveThing()
> t
Object {internal stuff only}
> t.GetSomething()
42

Goroutine gotcha

Doesn't work:

import "net/http"

func MyExportedFunc1(url string) {
    r, _ := http.Get(url)          // blocking call
    println(r)
}

Works:

import "net/http"

func MyExportedFunc2(url string) {
    go func() {
        r, _ := http.Get(url)      // blocking call
        println(r)
    }()
}

GOARCH is "js"

mycode_js.go
// +build js

import "github.com/gopherjs/gopherjs/js"

func Display(message string) {
    js.Global.Get("console").Call("log", message)
}
mycode_default.go
// +build !js

import "fmt"
import "os"

func Display(message string) {
    fmt.Fprintln(os.Stderr, message)
}

File sizes

Empty main function:

Import the sort package:

Import the fmt package:

NinchatClient

NinchatClient cont'd

Code base:

File size:

Estimated file size without direct browser API calls:

Performance

Ninchat profiling:

Internet says:

Debugging

Conclusion

Thank you