Webpack loader that simply compiles GO into WebAssembly. Can compile with Go or Tinygo. Also have the ability to use Docker so nothing need to be installed locally.
Install witn npm:
npm install --save-dev golang-loader
or with yarn:
yarn add -D golang-loader
Note:
go
also have to be installed. And either havego
inPATH
, or haveGOROOT
set.
With the default configuration you need to first install Go on your machine.
Then define a rule like this:
webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.go$/,
use: 'golang-loader',
},
],
},
};
Here is an example of a Hello, world! program:
src/main.go
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, world!")
}
To run the compiled Go code you need the glue code in wasm_exec.js
. It's found here: ${GOROOT}/misc/wasm/wasm_exec.js
Copy that file and put it in your src
folder.
OBS: The glue code provided in
wasm_exec.js
contains lots of polyfills because it's written to work in a browser and on a NodeJS environment. This will make Webpack panic since it can't resolve any NodeJS imports. The quick fix is to addresolve: { alias: { fs: false, crypto: false, util: false } }
to your webpack configuration. A better options is to just remove all the if-statements usingrequire
inwasm_exec.js
. They are not used in the Browser anyways.
The resulting module from the import is a fetch()
promise. Just pass that in to WebAssembly.instantiateStreaming
, and run it using the Go
class defined in wasm_exec.js
.
import wasm from './main.go';
import './wasm_exec';
const go = new Go();
WebAssembly.instantiateStreaming(wasm, go.importObject).then((module) => {
go.run(module.instance);
});
To be able to test this loader you need to use a development server, otherwise
CORS
will block the fetch for the.wasm
file. Also the dev server need to be able to handle theapplication/wasm
MIME type. webpack-dev-server work well on both counts.
To avoid the need to install Go on your machine you can set the docker
option to true
. This is the recommended way to use this loader.
webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.go$/,
use: {
loader: 'golang-loader',
options: { docker: true },
},
},
],
},
};
This of course need Docker to be installed and in your PATH
environment variable. When running this the first time it will download the golang
image, so it will take some time first run.
You can also compile using Tinygo. This have the advantage of producing significantly smalled wasm binaries. Just set the tinygo
options to true
.
webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.go$/,
use: {
loader: 'golang-loader',
options: { tinygo: true, docker: true },
},
},
],
},
};
This can be used with and without Docker. If not then you need to install Tinygo on your machine.
Note: Tinygo uses a different
wasm_exec.js
. You can find it here:${TINYGOROOT}/targets/wasm_exec.js
If you are using TypeScript the compiler will throw an error when importing a .go
file. To fix this you need to add a declaration for .go
modules. Create a declarations file and put this code in it. Also, while you are at it. Add a declaration for the Go class is wasm_exec.js
.
src/declarations.d.ts
declare module '*.go' {
const promise: Promise<Response>;
export default promise;
}
declare class Go {
importObject: WebAssembly.Imports;
readonly exited?: boolean;
run: (instance: WebAssembly.Instance) => Promise<void>;
}