tinygo webassembly 试用

发布时间 2023-11-01 09:48:17作者: 荣锋亮

主要是简单测试下tinygo 的使用,同时基于vite 进行web 的集成构建

wasm 生成

注意只测试标注类型支持比较多,其他的就没添加,其他类型的需要自己处理,这点上wasm-pack 处理的比较好

  • main.go
package main
 
//go:wasm-module
//export add
func add(x, y uint32) uint32 {
    return x + y + 100
}
 
//go:wasm-module
//export printName
func printName() int {
    return 1111
}
 
// main is required for the `wasi` target, even if it isn't used.
func main() {}
  • 构建
tinygo build -o main.wasm -target=wasi main.go

web 集成

会有wasm 文件的加载,webassembly 实例的初始化,以及方法的导出使用,这点vite 实际上支持支持wasm 文件的初始化
测试中我直接使用了tinygo 官方的示例,实际上可以参考vite 对于webassembly 支持进行调整

  • package.json
 
{
  "name": "tinygo",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "vite build",
    "dev": "vite",
    "preview": "vite preview"
  },
  "devDependencies": {
    "vite": "^4.5.0"
  }
}
  • index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World - Go</title>
  </head>
  <body>
    <!-- 
    The wasm_exec.js must come before our Javascript (index.js), 
    as it defines some global objects 
    -->
    <script type="module" src="./wasm_exec.js"></script> // 此文件是从tinygo 安装中拷贝的,比较重要
    <script type="module" src="./index.js"></script>
  </body>
</html>
  • index.js
    实际上就是调用webassembly 初始化工具类的方法
 
// Imports are from the demo-util folder in the repo
// https://github.com/torch2424/wasm-by-example/blob/master/demo-util/
import { wasmBrowserInstantiate } from "./instantiateWasm.js";
 
import wasmUrl from './main.wasm?url'
 
const go = new Go(); // Defined in wasm_exec.js. Don't forget to add this in your index.html.
 
const runWasmAdd = async () => {
  // Get the importObject from the go instance.
  const importObject = go.importObject;
 
  // Instantiate our wasm module
  const wasmModule = await wasmBrowserInstantiate(wasmUrl, importObject);
 
  // Allow the wasm_exec go instance, bootstrap and execute our wasm module
  go.run(wasmModule.instance);
 
  // Call the Add function export from wasm, save the result
  const addResult = wasmModule.instance.exports.add(2433, 24);
 
  const printName = wasmModule.instance.exports.printName();
  // Set the result onto the body
  document.body.textContent = `Hello World! addResult: ${addResult} -- printName: ${printName}`;
};
runWasmAdd();
  • instantiateWasm.js 是一个工具类
    实际上可以使用vite 的记性呢替代
 
export const wasmBrowserInstantiate = async (wasmModuleUrl, importObject) => {
    let response = undefined;
 
    if (!importObject) {
      importObject = {
        env: {
          abort: () => console.log("Abort!")
        }
      };
    }
 
    if (WebAssembly.instantiateStreaming) {
      response = await WebAssembly.instantiateStreaming(
        fetch(wasmModuleUrl),
        importObject
      );
    } else {
      const fetchAndInstantiateTask = async () => {
        const wasmArrayBuffer = await fetch(wasmModuleUrl).then(response =>
          response.arrayBuffer()
        );
        return WebAssembly.instantiate(wasmArrayBuffer, importObject);
      };
      response = await fetchAndInstantiateTask();
    }
 
    return response;
  };
  • 运行效果
yarn dev

 

  • 构建
yarn build

 

说明

vite 对于webassembly 的支持还是比较方便的,可以快速的进行项目打包

参考资料

https://tinygo.org/docs/guides/webassembly/wasi/
https://vitejs.dev/guide/features.html#webassembly
https://tinygo.org/docs/guides/webassembly/wasm/