这可能是世界上最简单的用Go来写WebAssembly的教程


这可能是世界上最简单的用Go来写WebAssembly的教程文章插图

  • 你认为 WebAssembly (WASM) 只用于图像处理、复杂的数学计算或者 Web 上的小小应用吗?
  • 你是否经常将 WASM 与 Web Workers 和 Service Workers 的概念混淆?
  • 你对 WASM 不感兴趣 , 是因为你认为现在的 Web 应用程序在未来 10 年里依旧是 JavaScript 主导?
  • 你是否想过用 JS 以外的语言做 Web 前端开发?
如果你不想细读 , 你可以看下我做的 demo 页面或者直接看下 go-wasm-cat-game-on-canvas-with-docker 这个项目 , 我会讲的简洁一些 , 尽量不浪费你的时间 。 以下是我这个项目的一些关键的代码解析 。
故事开始了我们的目标是给猫 做一个简单的小游戏:做一个小红点在手机上不停的移动 , 整个过程还有 HiFi 音乐 还有震动 。 整个项目我们会用 Golang (Go)这门语言来实现 , 包括 DOM 操作、逻辑还有相关的状态 。
而而而而而且 , 由于猫咪不会使用鼠标 , 我们还需要给猫爪 做一些点击触摸的交互 。
说一下我的理解!把 WASM 想象成一个 通用虚拟机(UVM, Universal Virtual Machine) 或者一个沙箱 , 你只需编写一次任何代码 , 它便可以在任何地方运行 。
WASM 是一个编译目标 , 而不是一种语言 。 就像你要同时针对 Windows , Mac OS 和 Linux 进行编译一样!
我不认为 WASM 会废弃 JS , 你可以有其他选择而不用付出任何代价 。
想象一下使用 Go , Swift , Rust , Ruby , C ++ , OCaml 或者其他语言的开发人员 。 现在 , 他们可以使用自己喜欢的语言来创建交互式 , 联网 , 快速 , 具有脱机功能的网站和Web 应用 。
你是否曾经参与过类似「一个项目是用一个代码仓库管理还是多个代码仓库管理?」问题的讨论?
好吧 , 不管你有没有 , 你现在也要想一下现在这个项目打算用一门语言实现还是多门语言实现了 。
当大家可以使用相同的技术栈时 , 一切都会变得更加容易 , 尤其是团队之间的沟通 。
你可以依旧使用 React 或者 Vue , 但你现在开始也可以不用使用 JS 来开发了 。
WASM 跟 Service Workers 还有 Web Workers 有什么区别?Service Workers 还有 Web Workers 允许应用在后台运行 , 也可以做到离线运行和缓存 。 它们模仿线程 , 无法访问DOM , 并且不能共享数据(仅能通过消息传递) , 只能在单独的上下文中运行 。 咦 , 其实我们甚至可以在其中运行 WASM 而不是 JS 。 对我来说 , 它们只提供一些具有特殊特权的抽象层 , 没有人说这些层必须执行 JS 。
Service Workers 还有 Web Workers 是浏览器上的功能 , 不是 JS 的专有功能 。
设置开发环境我们将使用 WASM , Go , JS 和 Docker(这个是可选的) 来进行开发 。
如果您不了解Go , 但了解 JS , 请 点击这里学习 Go , 然后再回来继续阅读 。 让我们从 Go WASM Wiki 开始 。
你可以使用安装在电脑本地的 go 版本 , 在这里我使用 Docker 的 golang:1.12-rc 镜像 。 只需在此处为 go 编译器设置两个 WASM 标志 。 在 main.go 中创建一个简单的 hello world 进行测试 。
$ GOOS=js GOARCH=wasm go build -o game.wasm main.gobuild_go: docker run --rm \ -v `pwd`/src:/game \ --env GOOS=js --env GOARCH=wasm \ golang:1.12-rc \ /bin/bash -c "go build -o /game/game.wasm /game/main.go; cp /usr/local/go/misc/wasm/wasm_exec.js /game/wasm_exec.js"现在 , 让我们利用好 Go 团队提供的 wasm_exec.js 代码 。 代码里的全局变量 Go 对 WASM 进行了初始化操作 , 我们不必自己从头开始做好任何 DOM 的实现 。 等我们编译好 wasm 文件后 , 它会获取 .wasm 文件并运行我们的游戏 。
总而言之 , 它应该看起来像这样:
body{height:100%;width:100%;padding:0;margin:0;background-color:#000000;color:#FFFFFF;font-family:Arial,Helvetica,sans-serif}放码过来!(当然是 Go 的码)要渲染我们的这个小游戏 , 这个标签应该足够了 。 我们可以直接从 Go 代码创建 DOM 结构和元素!这个 syscall/js 文件 (包含在标准 Go 库中)为我们处理了与 DOM 交互的方法 。
main() 方法我敢打赌 , 你很久没见过 main() 方法了。
package mainimport ( //"syscall/js")var ( // js.Value 可以是任意的 JS 对象、类型或者构造函数 window, doc, body, canvas, laserCtx, beep js.Value windowSize struct{ w, h float64 })func main() { setup()}func setup() { window = js.Global() doc = window.Get("document") body = doc.Get("body") windowSize.h = window.Get("innerHeight").Float() windowSize.w = window.Get("innerWidth").Float() canvas = doc.Call("createElement", "canvas") canvas.Set("height", windowSize.h) canvas.Set("width", windowSize.w) body.Call("appendChild", canvas) // 这个是小红点Canvas 对象 laserCtx = canvas.Call("getContext", "2d") laserCtx.Set("fillStyle", "red") //beep = window.Get("Audio").New("data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU2LjI1LjEwMQAAAAAAAAAAAAAA/+NAwAAAAAAAAAAAAFhpbmcAAAAPAAAAAwAAA3YAlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaW8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw////////////////////////////////////////////AAAAAExhdmYAAAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAN2UrY2LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/jYMQAEvgiwl9DAAAAO1ALSi19XgYG7wIAAAJOD5R0HygIAmD5+sEHLB94gBAEP8vKAgGP/BwMf+D4Pgh/DAPg+D5//y4f///8QBhMQBgEAfB8HwfAgIAgAHAGCFAj1fYUCZyIbThYFExkefOCo8Y7JxiQ0mGVaHKwwGCtGCUkY9OCugoFQwDKqmHQiUCxRAKOh4MjJFAnTkq6QqFGavRpYUCmMxpZnGXJa0xiJcTGZb1gJjwOJDJgoUJG5QQuDAsypiumkp5TUjrOobR2liwoGBf/X1nChmipnKVtSmMNQDGitG1fT/JhR+gYdCvy36lTrxCVV8Paaz1otLndT2fZuOMp3VpatmVR3LePP/8bSQpmhQZECqWsFeJxoepX9dbfHS13/////aysppUblm//8t7p2Ez7xKD/42DE4E5z9pr/nNkRw6bhdiCAZVVSktxunhxhH//4xF+bn4//6//3jEvylMM2K9XmWSn3ah1L2MqVIjmNlJtpQux1n3ajA0ZnFSu5EpX////uGatn///////1r/pYabq0mKT//TRyTEFNRTMuOTkuNaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq/+MQxNIAAANIAcAAAKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==")}