Skip to content

Frequently Asked Questions

Steve Yen edited this page Jun 28, 2022 · 11 revisions

Code Size

Why is GopherJS generated code so big?

GopherJS reimplements most of the Go runtime in Javascript, so that's a start. A lot of things import the fmt and reflect packages, which represents a sizable chunk of code. In general, GopherJS code is so large for reasons similar to the reason Go executables are so large: they're statically linked. In the Go case, literally; in the GopherJS case, metaphorically speaking, but the idea is similar.

What can I do to reduce the downloaded code size, or ameliorate the cost of downloading so much code?

  • Follow these performance tips
  • Try not to import packages you don't really need, like fmt.
  • Check out jsgo.io, which splits up GopherJS code into per-package files that are cached behind a CDN, essentially making GopherJS code non-monolithic / non-"statically linked", and increasing the likelihood and usefulness of caching at the package level.

Why not implement a tree-shaker / dead code eliminator?

We do! But that's both harder than it sounds, and not as useful as it sounds. "It's hard to dead code eliminate in Go in the presence of the reflect package. You can call arbitrary methods on types at runtime, for example. And importing pretty much anything ends up importing reflect." -- @Zeebo "Even in the absence of reflection, interfaces make it hard to prove what methods can safely be eliminated." -- @myitcv

External JavaScript Libraries

How can I reference variables and functions in an external JavaScript library?

You will need to use webpack and an "npm" distribution for the library you want to include. First run

npm install --save-dev webpack [external_library]

where [external_library] is the one you want to use (e.g. "pdfjs-dist").

In the external library code that is installed in node_modules (e.g. "node_modules/pdfjs-dist") find the "source code" version of the library (e.g. "node_modules/pdfjs-dist/lib/pdf.js"). This file will be the one that includes lines that start with exports. followed by some symbol in the library's API (e.g. exports.PDFWorker = pdfjsDisplayAPI.PDFWorker;).

Create a webpack.config.js file with the following contents in the top-level of your project:

const webpack = require("webpack");

module.exports = {
    entry: {
        pdf: "./node_modules/pdfjs-dist/lib/pdf.js"
    },
    output: {
        filename: "[name].inc.js",
        libraryTarget: "this",
        path: __dirname
    }
};

Note that you can add additional JavaScript source files after the line pdf: "./node_modules/pdfjs-dist/lib/pdf.js". For example:

entry: {
    pdf: "./node_modules/pdfjs-dist/lib/pdf.js",
    "pdf.worker": "./node_modules/pdfjs-dist/lib/pdf.worker.js",
    "pdf_viewer": "./node_modules/pdfjs-dist/web/pdf_viewer.js"
},

In your main.go file, include a line like this, near the top of the file:

//go:generate gopherjs build main.go pdf.inc.js -o app.js

Add any additional libraries after pdf.inc.js (e.g. pdf.worker.inc.js pdf_viewer.inc.js). You can also add -m to the end of the go:generate line to minify the Go code. The included JavaScript code (*.inc.js) will have been minified by default in webpack version >= 4.

//go:generate gopherjs build main.go pdf.inc.js -o app.js -m

Now run webpack on the command line in the top-level of your GopherJS project (where main.go is located). This should generate pdf.inc.js (and any other libraries) in that same top-level directory.

Finally, run go generate ./main.go, which will generate app.js containing your compiled GopherJS program, as well as all of the .inc.js libraries you added.

In your Go code, you can refer the to the exported symbols (e.g. exports.PDFWorker) using code like this:

var pdfWorker = js.Global.Get("PDFWorker")

You need to re-run the go generate ./main.go after any changes to your Go source code (in any of your Go files).

Clone this wiki locally