A compiler from Go to JavaScript for running Go code in a browser

GopherJS - A compiler from Go to JavaScript

GoDoc Sourcegraph Circle CI

GopherJS compiles Go code (golang.org) to pure JavaScript code. Its main purpose is to give you the opportunity to write front-end code in Go which will still run in all browsers.

Playground

Give GopherJS a try on the GopherJS Playground.

What is supported?

Nearly everything, including Goroutines (compatibility table). Performance is quite good in most cases, see HTML5 game engine benchmark. Cgo is not supported.

Installation and Usage

GopherJS requires Go 1.12 or newer.

Get or update GopherJS and dependencies with:

go get -u github.com/gopherjs/gopherjs

If your local Go distribution as reported by go version is newer than Go 1.12, then you need to set the GOPHERJS_GOROOT environment variable to a directory that contains a Go 1.12 distribution. For example:

go get golang.org/dl/go1.12.16
go1.12.16 download
export GOPHERJS_GOROOT="$(go1.12.16 env GOROOT)"  # Also add this line to your .profile or equivalent.

Now you can use gopherjs build [package], gopherjs build [files] or gopherjs install [package] which behave similar to the go tool. For main packages, these commands create a .js file and .js.map source map in the current directory or in $GOPATH/bin. The generated JavaScript file can be used as usual in a website. Use gopherjs help [command] to get a list of possible command line flags, e.g. for minification and automatically watching for changes.

gopherjs uses your platform's default GOOS value when generating code. Supported GOOS values are: linux, darwin. If you're on a different platform (e.g., Windows or FreeBSD), you'll need to set the GOOS environment variable to a supported value. For example, GOOS=linux gopherjs build [package].

Note: GopherJS will try to write compiled object files of the core packages to your $GOROOT/pkg directory. If that fails, it will fall back to $GOPATH/pkg.

gopherjs run, gopherjs test

If you want to use gopherjs run or gopherjs test to run the generated code locally, install Node.js 10.0.0 (or newer), and the source-map-support module:

npm install --global source-map-support

On supported GOOS platforms, it's possible to make system calls (file system access, etc.) available. See doc/syscalls.md for instructions on how to do so.

gopherjs serve

gopherjs serve is a useful command you can use during development. It will start an HTTP server serving on ":8080" by default, then dynamically compile your Go packages with GopherJS and serve them.

For example, navigating to http://localhost:8080/example.com/user/project/ should compile and run the Go package example.com/user/project. The generated JavaScript output will be served at http://localhost:8080/example.com/user/project/project.js (the .js file name will be equal to the base directory name). If the directory contains index.html it will be served, otherwise a minimal index.html that includes <script src="project.js"></script> will be provided, causing the JavaScript to be executed. All other static files will be served too.

Refreshing in the browser will rebuild the served files if needed. Compilation errors will be displayed in terminal, and in browser console. Additionally, it will serve $GOROOT and $GOPATH for sourcemaps.

If you include an argument, it will be the root from which everything is served. For example, if you run gopherjs serve github.com/user/project then the generated JavaScript for the package github.com/user/project/mypkg will be served at http://localhost:8080/mypkg/mypkg.js.

Environment Variables

There is one GopherJS-specific environment variable:

GOPHERJS_GOROOT - if set, GopherJS uses this value as the default GOROOT value,
                  instead of using the system GOROOT as the default GOROOT value

Performance Tips

Community

Getting started

Interacting with the DOM

The package github.com/gopherjs/gopherjs/js (see documentation) provides functions for interacting with native JavaScript APIs. For example the line

document.write("Hello world!");

would look like this in Go:

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

You may also want use the DOM bindings, the jQuery bindings (see TodoMVC Example) or the AngularJS bindings. Those are some of the bindings to JavaScript APIs and libraries by community members.

Providing library functions for use in other JavaScript code

Set a global variable to a map that contains the functions:

package main

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

func main() {
	js.Global.Set("pet", map[string]interface{}{
		"New": New,
	})
}

type Pet struct {
	name string
}

func New(name string) *js.Object {
	return js.MakeWrapper(&Pet{name})
}

func (p *Pet) Name() string {
	return p.name
}

func (p *Pet) SetName(name string) {
	p.name = name
}

For more details see Jason Stone's blog post about GopherJS.

Architecture

General

GopherJS emulates a 32-bit environment. This means that int, uint and uintptr have a precision of 32 bits. However, the explicit 64-bit integer types int64 and uint64 are supported. The GOARCH value of GopherJS is "js". You may use it as a build constraint: // +build js.

Application Lifecycle

The main function is executed as usual after all init functions have run. JavaScript callbacks can also invoke Go functions, even after the main function has exited. Therefore the end of the main function should not be regarded as the end of the application and does not end the execution of other goroutines.

In the browser, calling os.Exit (e.g. indirectly by log.Fatal) also does not terminate the execution of the program. For convenience, it calls runtime.Goexit to immediately terminate the calling goroutine.

Goroutines

Goroutines are fully supported by GopherJS. The only restriction is that you need to start a new goroutine if you want to use blocking code called from external JavaScript:

js.Global.Get("myButton").Call("addEventListener", "click", func() {
  go func() {
    [...]
    someBlockingFunction()
    [...]
  }()
})

How it works:

JavaScript has no concept of concurrency (except web workers, but those are too strictly separated to be used for goroutines). Because of that, instructions in JavaScript are never blocking. A blocking call would effectively freeze the responsiveness of your web page, so calls with callback arguments are used instead.

GopherJS does some heavy lifting to work around this restriction: Whenever an instruction is blocking (e.g. communicating with a channel that isn't ready), the whole stack will unwind (= all functions return) and the goroutine will be put to sleep. Then another goroutine which is ready to resume gets picked and its stack with all local variables will be restored.

GopherJS Development

If you're looking to make changes to the GopherJS compiler, see Developer Guidelines for additional developer information.

Comments
  • Support Go 1.13 and Go 1.14 both

    Support Go 1.13 and Go 1.14 both

    Build on Go 1.13 / Go 1.14 and one build support working on Go 1.12 Go 1.13 Go 1.14 three version.

    cd goproj/src
    git clone https://github.com/visualfc/gopherjs github.com/gopherjs/gopherjs
    cd github.com/gopherjs/gopherjs
    git checkout go1.13-dev
    go install -v
    
    1. This version build and install on Go 1.13 or Go 1.14. And one build support working on Go 1.12 1.13 1.14 three version and dynamic select internal compiler/natives/src.
    2. This version build and install on Go 1.12 and working on Go 1.12 only.
    3. if change install go version, please use -a flags to force rebuild packages. gopherjs build -a -v or gopherjs test -a -v
    • add internal/reflectlite for Go 1.13 Go 1.14
    • update syscall/js API for Go 1.13 Go 1.14 changes
    • support Go Module, build go project check go.mod ( use go env)
    • add -a (--force) flags to force rebuild packages
    • check installed go version for build ReleaseTags, support working Go 1.12 Go 1.13 Go 1.14 three version
  • Use a Javascript Map for Go Maps.  Improves performance of len() calls by orders of magnitude. šŸ—ŗļø

    Use a Javascript Map for Go Maps. Improves performance of len() calls by orders of magnitude. šŸ—ŗļø

    Overview

    https://github.com/gopherjs/gopherjs/issues/1135

    The performance of len() on maps brought me here, because it would call js Object.keys(myMap).Length. It was many orders of magnitude slower than len() in Go. It was a pitfall that those writing idiomatic go would fall into.

    This PR switches the backing implementation of Maps in GopherJS to ECMAScript 2015 Maps. These maps provide accounting so that Map.size can be called to make len() fast. I was hopeful that iterating maps would be faster, also, because the len of the map is used, but unfortunately that is not the case. However, it should be trivial to change the loop implementation to use [Map.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) when GopherJS adopts ECMAScript 2017.

    One thing to note: ES 2015 Maps do not return in random order. There is a pitfall, the I believe is acceptable, that someone could write GopherJS code that relies on the order of elements in a map, that does not work when run in the Go runtime.

    Using the benchmarks committed as part of this PR, with a size of 10000 elements: Master

    āœ— GOOS=linux gopherjs test ./... --bench="Benchmark.*"
    Using GOOS=linux and GOARCH=ecmascript in GopherJS is deprecated and will be removed in future. Use GOOS=js GOARCH=ecmascript instead.
    goos: js
    goarch: ecmascript
    BenchmarkSliceLen           	1000000000	         0.2600 ns/op
    BenchmarkMapLen             	    9886	    115719 ns/op
    BenchmarkMapNilCheck        	1000000000	         0.5070 ns/op
    BenchmarkMapNilElementCheck 	144578312	         8.328 ns/op
    BenchmarkSliceRange         	  226414	      5070 ns/op
    BenchmarkMapRange           	    6315	    183215 ns/op
    PASS
    ok  	benchmark/tom	7.682s
    

    This Branch Map len is ~6 orders of magnitude faster. Unfortunately, it appears element access and ranging has gotten ~20% worse, and ranging ~3% worse

    āœ— GOOS=linux gopherjs test ./... --bench="Benchmark.*"
    Using GOOS=linux and GOARCH=ecmascript in GopherJS is deprecated and will be removed in future. Use GOOS=js GOARCH=ecmascript instead.
    goos: js
    goarch: ecmascript
    BenchmarkSliceLen           	1000000000	         0.2820 ns/op
    BenchmarkMapLen             	1000000000	         0.5100 ns/op
    BenchmarkMapNilCheck        	1000000000	         0.2610 ns/op
    BenchmarkMapNilElementCheck 	104008665	        10.50 ns/op
    BenchmarkSliceRange         	  222222	      5094 ns/op
    BenchmarkMapRange           	    6082	    188096 ns/op
    PASS
    ok benchmark/tom	7.001s
    

    Testing

    It seems like the tests cover many more cases than manual testing ever could. I may have tunnel vision as the author of the PR, but I believe that passing CI tests should be considered good enough.

  • Health and future of the GopherJS open source project

    Health and future of the GopherJS open source project

    I'd like to open this tracking issue to open a discussion about the future of GopherJS, and the health of the project. The goal here is to try to answer the question: what does the future and roadmap look like for GopherJS? This is something that affects both the users and contributors to the project.

    Project Health

    Right now, the latest GopherJS 1.11-2 supports Go 1.11.x and works on macOS and Linux. On Windows or other OSes, it requires setting GOOS to one of two supported values, as documented at https://github.com/gopherjs/gopherjs#installation-and-usage, and system calls canā€™t work (which means gopherjs test canā€™t be used on those platforms). It can be described as functional, but with known limitations.

    There are many open issues and PRs that havenā€™t been fully reviewed and merged. In the last few months, there hasnā€™t been much activity in that regard. This is indicative of declining health of an open source project.

    At this time, there are 4 people with push rights to the main GopherJS repository: @neelance, myself, @hajimehoshi, and @myitcv as of recently (issue #799). To land a PR into master, it needs to go through code review and get a LGTM from at least one other maintainer. Richard has been quite busy working on Go WebAssembly and elsewhere. I have a full time job now, leaving me with less time to spend on GopherJS than before. Hajime and Paul have other commitments too. Being an open source project, weā€™re all volunteers working in spare time, so the resources we can dedicate to the project are limited.

    From my side, I can say that Iā€™m committed to doing my best to keep GopherJS running in its current state: on macOS and Linux, and compatible with the current Go releases (1.11 right now, 1.12 in a few months, 1.13, 1.14, etc.) for the foreseeable future. I canā€™t spend much more time on fixing the remaining issues and reviewing incoming PRs, at least nowhere near what Iā€™d like.

    I think it would be very helpful for contributors to have a better idea of what kind of PRs they can/should send and if it has a chance of being reviewed.

    Ways To Proceed

    We have a few possible strategies to choose from about what to do next. I will enumerate them below, and make a proposal for a suggested plan of action below. However, if there exists a better option that we haven't thought of, your input will be greatly appreciated.

    Option A: Do Nothing

    I want to make it clear that this is not a good option. However, this is the default outcome that happens unless we actively work towards one of the other options.

    This option is to do nothing and let things keep going as they are. This isnā€™t great, there are many stale PRs and itā€™s unclear to contributors if they should spend time creating new PRs, and whether their PR will be properly reviewed and eventually merged or closed.

    The outcome of this path is that the health of the open source project will continue to decline and it will be perceived closer to being a dead project.

    Option B: Limit Scope, Cull Contributions

    This option is to more actively limit the scope of contributions we accept, and communicate this (e.g., in README, a CONTRIBUTING file, etc.). Start closing PRs that are out of scope, since we donā€™t have the time required to get them reviewed.

    This option takes active work and time spent, as PRs need to be triaged and closed, sometimes even when there are valuable changes in them. However, the benefits are that the project health is improved and it becomes easier to make progress. Contributors are saved from spending time on out of scope PRs unnecessarily or kept wondering when their PR will be reviewed.

    Option C: Somehow Increase PR Reviewing Resources

    This option involves trying to get more help with reviewing existing PRs and getting them merged in. I donā€™t know how to make this happen. I donā€™t think we should be sacrificing quality and merging changes that arenā€™t thoroughly reviewed and tested. Many of the fixes require significant time and effort to investigate and understand how to resolve in the best way.

    This option would be great if it were viable, but we need to be realistic and understand it can't happen on its own.

    Suggested Plan

    From initial discussions with other maintainers, we are currently leaning towards Option B, limiting scope to be more manageable given the resources we have available, cutting down on feature development, but maintaining functionality and support for new Go releases as they come out. We should also do a better job of communicating it so that both contributors and users have a better idea of what to expect.

    However, Iā€™d like to invite input from the wider GopherJS community and hear feedback, suggestions for how we should proceed, and whatā€™s best for the future of GopherJS.

    From myself and other maintainers, I'd like to thank everyone who has contributed or used GopherJS over the years. I think it's a phenomenal project that has enabled people to build some really interesting things, and allowed us to use Go in more unexpected places! It should continue to work well for many years to come, until there's really no need to keep supporting it.

  • module-aware building

    module-aware building

    Now Go 1.11 introduces module-get, I suggest to change gopherjs build or other commands to be module-aware. For example, I'd want the below code to be workable:

    mkdir foo
    cd foo
    go mod init example.com/m
    go get github.com/gopherjs/gopherjs
    gopherjs build -tags=example github.com/hajimehoshi/ebiten/examples/sprites@master
    
  • Support for Go 1.12

    Support for Go 1.12

    When trying to go get goherjs/gopherjs using Go 1.12 (one commit newer than go1.12beta1, golang/go@9ed9df6ca2), I get the following error:

    $ go get -u github.com/gopherjs/gopherjs
    # github.com/gopherjs/gopherjs/compiler
    goget/src/github.com/gopherjs/gopherjs/compiler/compiler.go:20:9: undefined: ___GOPHERJS_REQUIRES_GO_VERSION_1_11___
    

    As I did not find any open issues about this, I just wanted to write about the workaround for this error I'm currently using until gopherjs gets support for Go 1.12.

    $ cd $GOPATH/src/github.com/gopherjs/gopherjs
    $ git remote add myitcv https://github.com/myitcv/gopherjs
    $ git fetch myitcv
    $ git checkout go1.12
    $ go get ./...
    

    This successfully compiles GopherJS for Go 1.12.

    $ gopherjs version
    GopherJS 1.12.0
    

    Cheers, Robin

  • Recursion Error in Iceweasel 49, trying to run the gopherjs/jquery example in README.md

    Recursion Error in Iceweasel 49, trying to run the gopherjs/jquery example in README.md

    I tried to run the jquery example in gopherjs/jquery, in my Iceweasel 49 (Firefox), note I have NoScript and few privacy addons enabled (uBlock Origin, HTTPS Everywhere, etc.)..

    Your current jQuery version is: 2.1.0
    too much recursion <Learn More> main.js:int:int
    

    go env (It may be useless):

    GOARCH="amd64"
    GOBIN=""
    GOEXE=""
    GOHOSTARCH="amd64"
    GOHOSTOS="linux"
    GOOS="linux"
    GOPATH="/home/user/gopath"
    GORACE=""
    GOROOT="/usr/lib/go"
    GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
    CC="gcc"
    GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build875613271=/tmp/go-build -gno-record-gcc-switches"
    CXX="g++"
    CGO_ENABLED="1"
    

    Edit: Found out more after debugging:

    It issues at main.js:2059:1, main.js is here: https://bpaste.net/raw/9652fed5cdcc

  • Endless unwinding call stack for seachJsObject

    Endless unwinding call stack for seachJsObject

    Today while attempting to integrate a test JS wrapper for the cache API released for webkit, a previous compile work but all new compiles consistently errored out due to a stack overflow error. Having established it is not the Go code in question I hoped any could help.

    The problem arises when goperhjs attempts to retrieving the functions argument type for a promise, but instead cycles out till stack memory is depleted

    WebCache Doc: https://developer.mozilla.org/en-US/docs/Web/API/Cache WebCache API: https://github.com/gu-io/gu/blob/develop/shell/cache/webcache/webcache.go#L62-L66

    Example Code:

    package main
    
    import (
    	"honnef.co/go/js/dom"
    
    	"github.com/gu-io/gu/shell/cache/webcache"
    )
    
    func main() {
    	doc := dom.GetWindow().Document().(dom.HTMLDocument)
    	body := doc.QuerySelector("body").(*dom.HTMLBodyElement)
    
    	webCache, err := webcache.New()
    	if err != nil {
    		body.AppendChild(doc.CreateTextNode(err.Error()))
    		body.AppendChild(doc.CreateElement("br"))
    	}
    
    	cache, err := webCache.Open("debi.v1") // issue arises here.
    	if err != nil {
    		body.AppendChild(doc.CreateTextNode(err.Error() + "\n"))
    		body.AppendChild(doc.CreateElement("br"))
    		return
    	}
    
    	err = cache.Add("http://localhost:8080/github.com/gu-io/gu/shell/")
    	if err != nil {
    		body.AppendChild(doc.CreateTextNode(err.Error()))
    		body.AppendChild(doc.CreateElement("br"))
    	}
    
    	res, err := cache.MatchPath("http://localhost:8080/github.com/gu-io/gu/shell/", webcache.MatchAttr{})
    	if err != nil {
    		body.AppendChild(doc.CreateTextNode(err.Error()))
    		body.AppendChild(doc.CreateElement("br"))
    		return
    	}
    
    	item := doc.CreateElement("div")
    	item.SetInnerHTML(string(res.Body))
    
    	body.AppendChild(item)
    	body.AppendChild(doc.CreateElement("br"))
    }
    

    Error Received:

    main.js:2058 Uncaught (in promise) RangeError: Maximum call stack size exceeded
        at searchJsObject (main.js:2058)
        at searchJsObject (main.js:2070)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2070)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2070)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2070)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2070)
        at searchJsObject (main.js:2067)
        //-------------------MORE---OF---THE---SAME--------//
        at searchJsObject (main.js:2070)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2070)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2067)
        at searchJsObject (main.js:2070)
        at $internalize (main.js:2081)
        at $internalize (main.js:2032)
        at v.$externalizeWrapper (main.js:1872)
    

    The above stack trace has been shortened due to its large length.

    GoperhJS Code In Question: https://github.com/gopherjs/gopherjs/blob/master/compiler/prelude/jsmapping.go#L343-L371

    It seems to be blowing up at the area of retrieving a pointer to the object response when using a promise.

    Expected Response: No SearchJsObject error when calling a Promise.

    Any help would truly be appreciated. I attempted to resolve the issues with some changes to the jsmapping.go region as linked above but failed, I assumed if we capped the depth since it was causing a repetition of the same t.Fields[0] and t pointer then it was properly a cyclical issue, but failed because the object received was not the appropriate *js.Object pointing to the cache instance. Irony is v matches the instance of the cache object in JS land but not sure how to resolve the cycle and attached it properly to a pointer in Go land within the jsmapping, but figuring out a means to stop the recurring call to check the same t and t.Field[0] which were the same with each call to searchJSObject and adequately get this area

    var f = t.fields[0];
            var o = searchJsObject(f.typ);
            if (o !== noJsObject) {
              var n = new t.ptr();
              n[f.prop] = o;
              return n;
            }
    

    executed properly seems to be the issue.

    Thanks.

  • compiler/natives/src/reflect: Optimize Swapper by swapping JS array elements directly (bypass reflection).

    compiler/natives/src/reflect: Optimize Swapper by swapping JS array elements directly (bypass reflection).

    Sort package was very slow and reflect when transpiled is bloated.

    Before natives were added

    gopherjs test sort --run=Slice --bench=Slice
    goos: linux
    goarch: js
    BenchmarkSortString1K_Slice 	     100	  14450000 ns/op
    BenchmarkStableInt1K_Slice  	      20	  55000000 ns/op
    BenchmarkSortInt64K_Slice   	       1	1486000000 ns/op
    PASS
    ok  	sort	4.913s
    

    After natives were added

    gopherjs test sort --run=Slice --bench=Slice -v
    goos: linux
    goarch: js
    BenchmarkSortString1K_Slice 	    2000	    984000 ns/op
    BenchmarkStableInt1K_Slice  	    2000	    993500 ns/op
    BenchmarkSortInt64K_Slice   	      20	  84300000 ns/op
    PASS
    ok  	sort	6.442s
    

    Result is around a one order of magnitude faster (and smaller generated code when using sort!)

  • proposal: Limit support to one GOOS value (primarily for stdlib).

    proposal: Limit support to one GOOS value (primarily for stdlib).

    The GopherJS compiler supports building output only for GOARCH=js value, and any GOOS value.

    That means it will produce valid and different output for this Go package, depending on which GOOS value is used:

    // +build plan9
    
    package p
    
    const Message = "It was a hot summer..."
    
    // +build !plan9
    
    package p
    
    const Message = "It was a cold winter..."
    

    Of course, it also supports cross-compiling, so one can produce different outputs by doing:

    $ GOOS=plan9 gopherjs build
    # hot summer
    
    $ GOOS=solaris gopherjs build
    # cold winter
    

    I propose we limit support to just a single fixed GOOS value.

    This is primarily meant to apply to the Go standard library, which we must manually apply overrides for in order to get it to build and work correctly for GOARCH=js. See https://github.com/gopherjs/gopherjs/commits/master/compiler/natives/src. However, I think we should apply for all packages for simplicity/consistency. Applying the limit to just Go stdlib but not 3rd party packages would be weird and unnecessary.

    The motivation is simple. It costs a lot of developer time to support Go standard library for GopherJS. Right now, I don't think this project can afford to continue to support all GOOS values. It's an open source project, with no funding, and most of the progress is made by volunteers contributing in their spare time in after work hours.

    The value gained from supporting multiple GOOS values is small. The cost is prohibitively high.

    The compiler will continue to be able to (theoretically) compile for many GOOS values, we're just not going to support GOOS values other than a single one that we pick.

  • Profiling and optimizing more heavyweight workload.

    Profiling and optimizing more heavyweight workload.

    Hi @neelance,

    In the past I've used GopherJS successfully for some medium-weight workloads, and performance has always been "good enough not be noticeable or cause any concerns."

    Recently I had a chance to use it for a more significant amount of work, and I'm seeing a quite large discrepancy between native and JS performance.

    Native Go:

    Read 1960081 of 1960081 bytes.
    Done loading track in: 95.778819ms
    

    Go compiled to JavaScript in browser:

    Read 1960081 of 1960081 bytes.
    Done loading track in: 27.944s
    

    The browser execution is around 300x slower. I see the browser tab reaching over 1 GB of RAM while loading the track.

    The workload can be seen here. It is loading a 2 MB binary file and then parsing it, doing a lot slice allocations and binary.Read. The 2 MB binary file (fetched via XHR) is wrapped in a bytes.NewReader (and another reader to count length read). Clearly, the Go code was written in the most easy to write and read way, without special considerations for performance.

    I tried to take a CPU profile in browser, and this is what I got:

    image

    Basically, I wanted to ask for some thoughts:

    1. Does the performance seem reasonable, or it possible there's some single issue/bad practice contributing to a lot of performance degradation?
      • I notice the newTrack func is called $blocking_newTrack, I wonder if that makes sense.
    2. Is the 500 MB - 1.1 GB of RAM usage in the browser table also expected? The native Go binary uses ~50 MB of RAM.
    3. Any other hints/tips on other ways I could profile it, other things to try to gain performance. For this task, I would be happy to get to less than 1~5 second track loading time (but that might not be realistic).
    4. General thoughts and comments if you have any. :)

    If you want to reproduce it, it should be straightforward. I've outlined steps in https://github.com/shurcooL/play/commit/e53557dd9c070ce0ec5251108249e5fa85333ae0#commitcomment-9101168. (I use gopherjs_serve_html for quicker iterations, but you can just use gopherjs build script.go and change index.html to use script.js instead.)

    Of course, I think the current results are pretty mind blowing, and being able to have it work at all is fantastic! Note that once the track finishes loading, I am able to get 30-60 FPS actually rendering it, so it's quite usable. At the same time, this could be a good benchmark to try various things and see how performance is affected. Hopefully, 30 seconds is just the beginning.

  • Structs are copied even when they are treated as immutable.

    Structs are copied even when they are treated as immutable.

    Passing a struct to a function is much slower than passing the contents of the struct. Skipping the copy for functions that do not set fields or take the address of the struct would improve performance.

    Real world example: (*image.RGBA).SetRGBA Toy benchmark: http://www.gopherjs.org/play/#/XeGJN8Ke0i

    BenchmarkStruct 2000000                824 ns/op
    BenchmarkArgs   2000000000               1.04 ns/op
    
  • compiler: factor out utility types for processing Go sources and errors.

    compiler: factor out utility types for processing Go sources and errors.

    This is the first step in reducing complexity of the compiler.Compile function.

    The new sources type represents all inputs into the package compilation and simplifies extracting useful information out of them. It is designed to have little business logic of its own and serves as a convenient bridge to other packages like go/types or astrewrite.

    The ErrorList type is extended with utility methods that reduce verbosity of the calling code.

    /cc @paralin

  • compiler panic `ast.Expr is *ast.IndexExpr, not *ast.Ident`

    compiler panic `ast.Expr is *ast.IndexExpr, not *ast.Ident`

    Error building graphjin/wasm https://github.com/dosco/graphjin/blob/master/wasm/main.go using gopherjs.

    unexpected compiler panic while building package "main": interface conversion: ast.Expr is *ast.IndexExpr, not *ast.Ident

    C:\workspace\graphql\graphjin\graphjin-master20221217\wasm>gopherjs.exe build "main.go"
    ā†[31m[compiler panic]  unexpected compiler panic while building package "main": interface conversion: ast.Expr is *ast.IndexExpr, not *ast.Ident
    
    Original stack trace:
       goroutine 1 [running]:
      runtime/debug.Stack()
            C:/Users/DESKTOP-1C942AU/scoop/apps/go/current/src/runtime/debug/stack.go:24 +0x65
      github.com/gopherjs/gopherjs/compiler.bailout(...)
            C:/Users/DESKTOP-1C942AU/go/pkg/mod/github.com/gopherjs/[email protected]/compiler/utils.go:814
      github.com/gopherjs/gopherjs/compiler.Compile.func1()
            C:/Users/DESKTOP-1C942AU/go/pkg/mod/github.com/gopherjs/[email protected]/compiler/package.go:138 +0x129
    
  • GopherJS Playground 2.0

    GopherJS Playground 2.0

    The GopherJS playground has been doing its job very well, but I think it may be time to give it an overhaul. Here is a list of improvements I would like to make (in no particular order):

    • Migrate to a modern frontend framework. Currently we are using some ancient version of AngularJS is no longer supported. In my experiments, vecty mostly works with GopherJS even though it no longer supports it officially. vugu or go-app might be another interesting option.
    • Make it possible to show generated JavaScript code for the main package. This is something our users have requested in the feedback survey, and I also wished for it on multiple occasions.
    • Implement "advanced" codepen-style mode, which allows the user to provide HTML and CSS, and have results executed in an iframe sandbox.
    • Use play.golang.org [^1] instead of https://snippets.gopherjs.org to save snippets. I believe the latter is still being maintained by @dmitshur, and potentially he wouldn't have to keep doing it indefinitely. But what is even more appealing to me is that it would make the two playgrounds more interoperable: you would be able to open the same snippet with the same ID in either gopherjs or the official playground and compare behavior.
    • Use better code editor, which supports automatic indentation and maybe even syntax highlighting.

    I think this would be a great contribution for someone new to the project, since it doesn't require getting far in the weeds of the compiler, but does give an opportunity to touch the internals a little bit.

    [^1]: Snippets can be saved by POST'ing its text to https://play.golang.org/share, which will return snippet ID. Given the ID, the snippet can be read by GET'ing https://play.golang.org/p/${id}.go. Both endpooints allow cross-origin requests, so they would work find on our playgound.

  • compiler/natives, compiler/gopherjspkg: simplify file embedding by using embed package, if it's a good fit

    compiler/natives, compiler/gopherjspkg: simplify file embedding by using embed package, if it's a good fit

    GopherJS relies on vfsgen to embed some files. vfsgen predates Go's embed package, so I wanted to see if it's no longer needed. I tried it out on the embed-natives branch.

    It turned out to work well to replace vfsgen with embed for the compiler/natives package; see commit 6078b6b9c0e0a5d41a8d8e5ff4685980e6adb1e7 and its commit message for some minor details.

    For the compiler/gopherjspkg, I haven't found a way to do it that I'm happy with. It's running into embed's restriction files cannot be embedded from the parent directory, so embedding files in js and nosync directories at the top level can only be done from that directory (which is where the gopherjs command currently sits) or from js and nosync directories themselves (which is where those packages sit). It's possible to make extra copies, or to try to do the embedding in the gopherjs command and provide it to the compiler package as an input (this makes the API of compiler package harder to use). Neither of those options seem better than the current use of vfsgen.

    It would be nice to remove reliance on vfsgen completely, but since there doesn't seem to be a clean path to do it, it seems fine to leave gopherjspkg alone for now and at least tackle natives.

    Any thoughts? I can open a PR to merge the current version of the embed-natives branch into master.

  • SOCK_NONBLOCK / SOCK_CLOEXEC syscall issues

    SOCK_NONBLOCK / SOCK_CLOEXEC syscall issues

    Running a sample socket code throws the following syscall issues:

    package main
    import "github.com/gofiber/fiber/v2"
    
    func main() {
    	app := fiber.New()
    
    	app.Get("/get", func(c *fiber.Ctx) error {
    		return c.SendString("Hello from GET!")
    	})
    
    	app.Post("/post", func(c *fiber.Ctx) error {
    		return c.SendString("Hello from POST!")
    	})
    
    	_ = app.Listen(":3000")
    }
    
    

    Error:

    ../../../github.com/valyala/[email protected]/socket_other.go:11:48: SOCK_NONBLOCK not declared by package syscall
    ../../../github.com/valyala/[email protected]/socket_other.go:11:70: SOCK_CLOEXEC not declared by package syscall
    

    GopherJS version:

    GopherJS 1.18.0+go1.18.5

    Build cmd:

    GOOS=js GOARCH=ecmascript gopherjs build main.go

  • Create a GopherJS documentation site

    Create a GopherJS documentation site

    I think one of the biggest pain points for GopherJS users (current and potential) is the lack of accessible and comprehensive user documentation. We have some bits scattered between the README, docs directory and wiki, but I wouldn't call that user-friendly.

    A simple site with organized tutorials, documentation, FAQs, etc. would be a great improvement. It doesn't have to be anything sophisticated, just a static site would be more than enough, most of the effort would be dedicated to simply organizing the existing material and maybe filling in some gaps.

    We already have GitHub Pages repository we could use. We could also pick up a per-made template like Docsy. AFAICT that's what TinyGo uses for their web site.

A JavaScript interpreter in Go (golang)

otto -- import "github.com/robertkrimen/otto" Package otto is a JavaScript parser and interpreter written natively in Go. http://godoc.org/github.com/

Jan 2, 2023
ECMAScript/JavaScript engine in pure Go

goja ECMAScript 5.1(+) implementation in Go. Goja is an implementation of ECMAScript 5.1 in pure Go with emphasis on standard compliance and performan

Jan 1, 2023
Automated compiler obfuscation for nim

Denim Makes compiling nim code with obfuscator-llvm easy! Windows only for now, but do you even need compiler obfuscation on other platforms? Setup In

Dec 31, 2022
Promise to the Go compiler that your Reads and Writes are well-behaved

noescape go get lukechampine.com/noescape noescape provides Read and Write functions that do not heap-allocate their argument. Normally, when you pas

Dec 22, 2022
Go compiler for small places. Microcontrollers, WebAssembly, and command-line tools. Based on LLVM.

TinyGo - Go compiler for small places TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and comma

Jan 4, 2023
JIT compiler in Go

jit-compiler This is a Golang library containing an x86-64 assembler (see 'asm/') and a higher level intermediate representation that compiles down in

Dec 24, 2022
GopherLua: VM and compiler for Lua in Go

GopherLua: VM and compiler for Lua in Go. GopherLua is a Lua5.1 VM and compiler written in Go. GopherLua has a same goal with Lua: Be a scripting lang

Jan 9, 2023
A Lua 5.3 VM and compiler written in Go.

DCLua - Go Lua Compiler and VM: This is a Lua 5.3 VM and compiler written in Go. This is intended to allow easy embedding into Go programs, with minim

Dec 12, 2022
Compiler for a small language into x86-64 Assembly

Compiler This project is a small compiler, that compiles my own little language into X86-64 Assembly. It then uses yasm and ld to assemble and link in

Dec 13, 2022
The Project Oberon RISC compiler ported to Go.

oberon-compiler This is a port of the Project Oberon compiler for RISC-5 (not to be confused with RISC-V) from Oberon to Go. The compiled binaries can

Dec 6, 2022
The golang tool of the zig compiler automatically compiles different targets according to the GOOS GOARCH environment variable. You need to install zig.

The golang tool of the zig compiler automatically compiles different targets according to the GOOS GOARCH environment variable. You need to install zig.

Nov 18, 2022
Logexp - Logical expression compiler for golang

Logical Expression Compiler Functions: - Compile(exp string) - Match(text string

Jan 24, 2022
A compiler for the ReCT programming language written in Golang

ReCT-Go-Compiler A compiler for the ReCT programming language written in Golang

Nov 30, 2022
Transpiling C code to Go code

A tool for transpiling C code to Go code. Milestones of the project: Transpiling project GNU GSL. Transpiling project GTK+. Notes: Transpiler works on

Dec 19, 2022
Transpiling fortran code to golang code

f4go Example of use > # Install golang > # Compile f4go > go get -u github.com/Konstantin8105/f4go > cd $GOPATH/src/github.com/Konstantin8105/f4go > g

Sep 26, 2022
Grumpy is a Python to Go source code transcompiler and runtime.

Grumpy: Go running Python Overview Grumpy is a Python to Go source code transcompiler and runtime that is intended to be a near drop-in replacement fo

Jan 7, 2023
Transform Go code into it's AST

Welcome to go2ast ?? Transform Go code into it's AST Usage echo "a := 1" | go run main.go Example output []ast.Stmt { &ast.AssignStmt {

Dec 13, 2022
Compile Go regular expressions to Go code

regexp2go regexp2go is an alternate backend for the regexp package that allows to perform ahead-of-time compilation of regular expressions to Go code.

Jul 11, 2022
Syntax-aware Go code search, based on the mvdan/gogrep
Syntax-aware Go code search, based on the mvdan/gogrep

gogrep WIP: this is an attempt to move modified gogrep from the go-ruleguard project, so it can be used outside of the ruleguard as a library. Acknowl

Nov 9, 2022