2

golang installation

Download through official address MacOS can also be quickly installed brew

$ brew install golang

$ go version
go version go1.17.2 darwin/arm64

golang environment test

Create a new file main.go and write:

package main

import "fmt"

func main() {
  fmt.Println("Hello World!")
}

Executing go run main.go will output:

$ go run main.go
Hello World!
If GO MODULES is enabled, you need to initialize the module go mode init GO111MODULE=auto .

Package golang as WASM

There are usually two packaging methods, one is that golang comes with, and the other is to use tinygo . It is recommended to use tinygo because the compiled wasm module is smaller.

  • Use golang native compilation

    Before compiling the wasm module, you need to set the golang cross-compilation parameters, the target system GOOS=js and the target architecture GOARCH=wasm , compile the wasm module:

    // macos
    $ GOOS=js GOARCH=wasm go build -o main.wasm
    
    // windows 临时设置 golang 环境参数(仅作用于当前CMD)
    $ set GOOS=js 
    $ set GOARCH=wasm
    $ go build -o main.wasm
  • Compile with tinygo

    Directly in accordance with official document be installed, MacOS as follows:

    $ brew tap tinygo-org/tools
    $ brew install tinygo
    
    $ tinygo version
    tinygo version 0.20.0 darwin/amd64 (using go version go1.17.2 and LLVM version 11.0.0)

    Use the following command to main.go again:

    $ tinygo build -o main-tiny.wasm
  • Package file size comparison

    $ du -sh ./*.wasm
    228K    ./main-tiny.wasm
    1.9M    ./main.wasm

Run in the browser

If you want to run main.wasm in the browser, you first need the JS glue code. Golang has provided it for us, so copy it directly. It should be noted that tinygo and natively compiled glue code, copy the corresponding according to the specific situation:

// 原生编译
$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

// tinygo编译
$ cp "$(tinygo env TINYGOROOT)/targets/wasm_exec.js" ./wasm_exec_tiny.js

Second, you need a HTML entry file, create a index.html file, and write the following code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./wasm_exec_tiny.js"></script>
</head>
<body>
  <script>
    const go = new Go(); // wasm_exec.js 中的定义
    WebAssembly.instantiateStreaming(fetch('./main-tiny.wasm'), go.importObject)
      .then(res => {
        go.run(res.instance); // 执行 go main 方法
      });
  </script>
</body>
</html>

Finally, create a http server let it run~

// python
$ python3 -m http.server
$ python2 -m SimpleHTTPServer

// node
$ npm i -g http-server
$ hs

// gp
$ go get -u github.com/shurcooL/goexec
$ goexec 'http.ListenAndServe(`:8080`, http.FileServer(http.Dir(`.`)))'

Exception record

  • Through the service from node's http-server, loading will report an error:

    > TypeError: Failed to execute 'compile' on 'WebAssembly': Incorrect response MIME type. Expected 'application/wasm'.

The reason is that the content-type of the application/wasm; charset=utf-8 , which should be application/wasm . The known solution is to modify the initialization method of wasm in HTML as follows:

fetch('./main-tiny.wasm')
  .then(res => res.arrayBuffer())
  .then(buffer => {
    WebAssembly.instantiate(buffer, go.importObject)
      .then(res => {
        go.run(res.instance);
      })
  })

shushushu
551 声望31 粉丝