MyGo浏览器运行指南:WebAssembly+WebGL2让原生UI跑进网页
MyGo浏览器运行指南:WebAssembly+WebGL2让原生UI跑进网页
MyGo 是一个用 Go 语言开发桌面应用的开源框架,支持 Web 前端与纯 Go 绘制的原生 UI 两种界面。它最有意思的一点是:用纯 Go 写成的原生 UI 应用,代码几乎不用改动,就能编译成 WebAssembly 跑进浏览器,并由 WebGL 2 实时渲染出完整的界面。这篇指南面向新手,讲清楚它背后的原理、两条命令的上手步骤,以及浏览器里哪些能力可用、哪些暂不可用。
一、原生 UI 为什么能跑进浏览器?
传统印象里,"桌面应用"意味着要安装、要打包、要依赖系统组件。而 MyGo 的浏览器模式让同一份 Go 代码直接在网页标签页里运行,原理可以拆成两部分:
1. Go 代码编译为 WebAssembly
mygo 命令行工具会把你的应用以 GOOS=js GOARCH=wasm 编译成 .wasm 文件,再配合 Go 官方的 wasm_exec.js 加载器在页面中启动。也就是说,浏览器里跑的是你的 Go 代码本身,而不是某个 Web 模拟层。相关实现位于 cmd/mygo/web.go。
2. WebGL 2 负责全部画面
原生 UI 的窗口在页面上是一个 <canvas>,由 WebGL 2 绘制——与 Linux 桌面版使用同一个渲染器、同一套着色器。具体细节见 internal/gpu/gl/ 与 internal/web/ 两个模块,docs/architecture.md 的 "Browsers" 一节有更完整的架构说明:
- 绘制:按设备像素比(device pixel ratio)用 WebGL 2 逐帧渲染,只有内容有变化时才绘制,Liquid Glass 等特效与桌面版表现一致;浏览器若不支持 WebGL 2,会自动退回内存绘制 + 2D canvas 的降级方案
- 文本:直接借用浏览器自己的字体系统——找字体、缺字回退、换行与双向排版(bidi)都与普通网页一致,
system-ui就是系统字体 - 输入:鼠标点击计数、滚轮与触控板、键盘、输入法(IME)组合输入、浏览器剪贴板的复制/剪切/粘贴均可用
- 帧循环:通过
requestAnimationFrame驱动,页面被隐藏时自动暂停,切回标签页时恢复
💡 对新手来说一句话总结:画面走 WebGL 2,文字走浏览器字体,逻辑就是你原来的 Go 代码。
二、两条命令快速上手:浏览器开发流程
开发模式:mygo dev -web
在一个原生 UI 项目(mygo init -template native 创建的)里执行:
mygo dev -web
它会自动完成四件事:
- 把应用编译成 WebAssembly,在
http://localhost:5174提供页面并打开浏览器 - 监听 Go 代码变化,自动重新编译并刷新页面(构建失败时页面保留上一个可用版本,并在其上显示报错原因)
- 提供一组快捷键:按
r重新构建、o重新打开页面、q退出 - 默认端口被占用时自动尝试下一个可用端口(可用
-port指定,-open=false可关闭自动打开)
开发模式的完整实现见 cmd/mygo/web.go,CLI 参数说明见 docs/cli.md。
生产构建:mygo build -platform web
mygo build -platform web
产出物是一个纯静态站点(默认位于 <out>/web 目录),包含:
| 文件 | 说明 |
|---|---|
index.html |
加载页面,带加载中的转圈动画 |
wasm_exec.js |
Go 官方 WebAssembly 加载器(与编译器版本严格匹配) |
<名称>.<内容哈希>.wasm |
应用本体,文件名带内容摘要,方便浏览器长期缓存 |
icon |
配置了图标时的应用图标 |
因为是静态文件,它可以放到任何静态服务器、对象存储或 CDN 上,无需后端。构建逻辑见 cmd/mygo/web.go,浏览器行为的官方文档是 docs/ui/browsers.md。
不走 CLI:纯 Go 方式
不想依赖 mygo 命令时,两条 Go 标准命令也能完成:
GOOS=js GOARCH=wasm go build -o app.wasm .
cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" .
然后写一个最小的 HTML,用 WebAssembly.instantiateStreaming 加载 app.wasm 即可,完整页面模板参考 docs/ui/browsers.md。注意务必通过 HTTP 提供服务(WASM 需要 application/wasm 内容类型),直接用 file:// 打开会失败。
三、浏览器里哪些能力可用?
以仓库里的计数器示例 examples/counter-native/main.go 为例——它的全部界面就是一段 Go 代码(ui.Column + ui.Button + ui.Textf),在桌面和浏览器中运行同一份源码。各能力的支持情况如下:
✅ 浏览器中可用的能力
| 能力 | 浏览器中的表现 |
|---|---|
| 绘制与特效 | WebGL 2 实时渲染,玻璃拟态等特效与桌面一致 |
| 文本渲染 | 使用浏览器字体,支持缺字回退与双向排版 |
| 指针 / 键盘 | 点击、滚轮、触控板、按键均正常 |
| 输入法 | 在光标处正常组合输入 |
| 路由 | 浏览器的前进/后退按钮可走应用内的页面(URL 片段如 #/notes/42),刷新或外链直达也能正确恢复位置 |
| 文件拖放 | 拖文件进窗口可用;浏览器拿不到本地路径,框架会在内部保留最近 16 次拖放的文件,os.ReadFile 等标准库调用照常工作 |
| 右键菜单 | 以 HTML 菜单形式显示在页面上 |
| 暗色模式 | 跟随浏览器的"减少动态""增强对比"等设置,也可在根元素上手动指定 |
| 弹窗 | Dialog.Message 使用浏览器的 alert / confirm |
| 打开链接 | Shell.OpenExternal 会打开新标签页 |
⚠️ 浏览器中暂不可用的能力
网页窗口、应用菜单与 Dock 菜单、系统托盘、通知、全局快捷键、文件选择对话框、非文件类的数据拖放,以及辅助功能(读屏器等)在浏览器中没有对应的宿主能力,框架会明确报告"不支持"而不是静默失败。
📌 选型建议:如果你的核心界面是"内容型"的(编辑、浏览、可视化),浏览器模式基本无感;如果重度依赖托盘、通知、全局快捷键,则更适合打包成桌面应用。
四、构建产物有多大?
WebAssembly 体积是很多人关心的问题,官方给出的参考数据:
- 计数器示例:8.2 MB(gzip 压缩后 2.2 MB)
- 包含全部组件的文档演示应用:9.8 MB(gzip 后 2.6 MB)
体积可控的关键在于:面向浏览器的构建会自动剔除只服务于网页前端的模块(IPC、自定义协议、TypeScript 客户端生成器、自动更新及其加解密代码等),且为浏览器新增的代码不会反向加进桌面构建里。生产构建还会通过 mygo_noinspector 标签再省掉约 350 KB 的内置检查器。
五、把应用嵌入自己的网页
mygo build -platform web 生成的页面默认让窗口铺满整个页面。如果你想把它嵌进已有网站:
- 在页面中放一个 ID 为
mygo的元素,窗口会填满该元素;找不到该元素则填满整个页面 - 窗口的大小完全由页面控制(Go 端设置的宽高、位置、标题栏选项在浏览器中不生效),可以用 CSS 布局把它放进任意位置
- 后打开的窗口会覆盖先前的窗口,最后打开窗口对应的标题会作为页面标题
六、相关资料与源码索引
- 浏览器模式官方文档:docs/ui/browsers.md
- CLI 命令说明(
dev -web/build -platform web):docs/cli.md - 架构总览(含 "Browsers (internal/web)" 小节):docs/architecture.md
- CLI 的 Web 构建与热重载实现:cmd/mygo/web.go
- 浏览器后端(窗口、canvas、事件循环):internal/web/
- js/wasm 构建时选用的后端入口:backend_js.go
- OpenGL / WebGL 2 渲染器:internal/gpu/gl/
- 可跑在浏览器里的示例应用:examples/counter-native/main.go、examples/menubar-native/main.go
七、写在最后
MyGo 的浏览器模式本质上做了一次"桌面到网页的无缝迁移":Go 逻辑编译为 WebAssembly,画面交给 WebGL 2,文字和输入复用浏览器的成熟能力。两条命令(mygo dev -web 开发、mygo build -platform web 发布)即可完成从桌面应用到静态网页站点的切换,产物体积小、部署简单,非常适合让已有的原生 UI 应用获得一个"免安装"的 Web 版本。