软件技术学习笔记

个人博客,记录软件技术与程序员的点点滴滴。

Golang WebAssembly起步

从GoLang 1.11开始,直接支持编译目标为WebAssembly,不需要安装额外的TidyGo。

本文演示GoLang WebAssembly Hello World程序。

1. 编写main.go

package main

import "fmt"

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

2. 设置GOARCHGOOS环境变量,编译目标为wasm文件

Linux:

$ GOARCH=wasm GOOS=js go build -o lib.wasm main.go
$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

Windows Powershell:

$Env:GOOS='js'
$Env:GOARCH='wasm'
go build -o main.wasm

3. 复制wasm_exec.js到目标位置

Linux:

$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

Windows(需看清Go的安装目录):

copy C:\Apps\Go\misc\wasm\wasm_exec.js .

4. 编写index.html文件加载WASM

从 $GOROOT/misc/wasm/wasm_exec.html 复制过来改改可以了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>GoLang WebAssembly</title>
</head>
<body>
    <script src="wasm_exec.js"></script>
    <script>
        if (!WebAssembly.instantiateStreaming) { // polyfill
            WebAssembly.instantiateStreaming = async (resp, importObject) => {
                const source = await (await resp).arrayBuffer();
                return await WebAssembly.instantiate(source, importObject);
            };
        }

        const go = new Go();
        let mod, inst;
        WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
            mod = result.module;
            inst = result.instance;
            document.getElementById("runButton").disabled = false;
        }).catch((err) => {
            console.error(err);
        });

        async function run() {
            console.clear();
            await go.run(inst);
            inst = await WebAssembly.instantiate(mod, go.importObject); // reset instance
        }
    </script>
    <button onClick="run();" id="runButton" disabled>Run</button>
</body>
</html>

5. 确认结果

使用python -m http.server打开一个Web服务,浏览器打开http://127.0.0.1:8000/,点击“Run”按钮。

F12打开浏览器的控制台,看到如下内容:

Hello world