TL;DR: GopherJS aims to provide full compatibility with regular Go, but JavaScript runtime introduces unavoidable differences.
Go ecosystem is broad and complex, which means there are several dimensions in which different levels of compatibility can be achieved:
- Go Language Specification: full compatibility. With the exception of several minor differences documented below, GopherJS should be fully compliant with the language specification (e.g. type system, goroutines, operations, built-ins, etc.).
- Go Standard Library: mostly compatible. GopherJS attempts to support as much of standard library as possible, but certain functionality is impossible or difficult to implement within the JavaScript runtime, most of which is related to os interaction, low-level runtime manipulation or
unsafe
. See package compatibility table and syscall support for details. - Build system and tooling: partially compatible. The
gopherjs
CLI tool is used to build and test GopherJS code. It currently supports buildingGOPATH
projects, but Go Modules support is missing (see gopherjs#855). Our goal is to reach complete feature parity with thego
tool, but there is a large amount of work required to get there. Other notable challenges include:- Limited compiler directive (a.k.a. "pragma") support. Those are considered compiler implementation-specific and are generally not portable.
- GopherJS ships with standard library augmentations, that are required to make it work in a browser. Those are applied on-the-fly during the build process and are generally invisible to any third-party tooling such as linters. In most cases that shouldn't matter, since they never change public interfaces of the standard library packages, but this is something to be aware of.
- Runtime debuggers and profilers. Since GopherJS compiles Go to JavaScript, one must use JavaScript debuggers and profilers (e.g. browser dev tools) instead of the normal Go ones (e.g. delve or pprof). Unfortunately, limited sourcemap support makes this experience less than ideal at the moment.
In general, for a given release of GopherJS the following statements should be true:
-
GopherJS compiler can be built from source with the latest stable Go release at the time when the GopherJS release is created, or any newer Go release.
Example: you can build GopherJS
1.12-3
with Go1.12
or newer. -
GopherJS compiler can build code using standard library of a specific Go version, normally the latest stable at the time of GopherJS release. In most cases, it should be compatible with all patch versions within the minor Go version, but this is not guaranteed.
Example: GopherJS
1.16.0+go1.16.2
(see developer documentation about GopherJS versioning schema) can build code with GOROOT pointing at Go1.16.0
or1.16.2
, but not at Go1.15.x
or1.17.x
. -
Users can use older GopherJS releases if they need to target older Go versions, but only the latest GopherJS release is officially supported at this time.
Note: we would love to make GopherJS compatible with more Go releases, but the amount of effort required to support that exceeds amount of time we currently have available. If you wish to lend your help to make that possible, please reach out to us!
First of all, please check the list of known issues below, package support table, as well as open issues on GitHub. If the issue is already known, great! You've saved yourself a bit of time. Feel free to add any extra details you think are relevant, though.
If the issue is not known yet, please open a new issue on GitHub and include the following information:
- Go and GopherJS versions you are using.
- In which environment do you see the issue (browser, nodejs, etc.).
- A minimal program that behaves differently when compiled with the regular Go compiler and GopherJS.
Now that the issue exists, we (GopherJS maintainers) will do our best to address it as promptly as we can. Note, however, that all of us are working on GopherJS in our spare time after our job and family responsibilities, so we can't guarantee an immediate fix.
🚧 If you would like to help, please consider submitting a pull request with a fix. If you are unsure of the best way to approach the issue, we will be happy to share whatever knowledge we can! 😃
For the most part, GopherJS shouldn't require any special support for the code that only uses supported standard packages.
However, if you do need to provide different implementations depending on the target architecture, you can use build constraints to do so. By default, GopherJS uses GOOS=js GOARCH=ecmascript
, which can be used in build constraints:
//go:build js
— the source will be used for GopherJS and Go WebAssembly, but not for native builds.//go:build js && ecmascript
— the source will be used for GopherJS only, and not WebAssembly or native builds.//go:build js && wasm
— the source will be used for Go WebAssembly, and not GopherJS or native builds.//go:build gopherjs
— the source will be used only by the GopherJS compiler, regardless of theGOOS
andGOARCH
. Use this constraint for sources that are not portable to other Go implementations.
Also be careful about using GopherJS-specific packages (e.g. github.com/gopherjs/gopherjs/js
) or features (e.g. wrapping JavaScript objects into Go structs), since those won't work outside of GopherJS.
GopherJS implements syscall/js
package, so it should be able to run most code written for WebAssembly. However, in practice this topic is largely unexplored at this time.
It is worth noting that Go predeclares both architecture-independent numeric types (int32
, int64
, etc.) and ones with implementation-specific sizes (int
, uintptr
, etc.). Pay attention to this distinction to avoid portability issues between 32-bit and 64-bit platforms.
🚧 If you have first-hand experience with this, please consider adding it to this section!
- Bit shifts of a negative amount (e.g.
42 << -1
) panic in Go, but not in GopherJS. - See also open issues and known failing compiler tests.