外观
浏览器中的原生 UI
原生 UI 应用编译为 WebAssembly 后也能在浏览器中运行:它的窗口显示在 页面的 canvas 上,由与 Linux 相同的渲染器用 WebGL 2 和相同的着色器 绘制。应用本身无需任何改动:
go
func main() {
s := &counter{}
mygo.App.WhenReady(func() {
mygo.NewWindow(mygo.WindowOptions{Title: "Counter", Content: ui.View(s.view)})
})
if err := mygo.App.Run(); err != nil {
log.Fatal(err)
}
}mygo dev -web 在浏览器中进行开发:它把应用编译为 WebAssembly,在 http://localhost:5174 提供服务并打开它,你编辑时自动重新构建并重新 加载页面。mygo build -platform web 把它构建到 <out>/web,一个可以 从任何地方提供的静态站点:index.html、Go 的 wasm_exec.js 和应用的 WebAssembly(参见 CLI)。
sh
mygo dev -web
mygo build -platform web不使用 CLI 时,为 js/wasm 构建,并把 Go 的 WebAssembly 加载器放在 旁边:
sh
GOOS=js GOARCH=wasm go build -o app.wasm .
cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" .然后在页面中加载它:
html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>html, body { margin: 0; height: 100%; }</style>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("app.wasm"), go.importObject).then((r) => go.run(r.instance));
</script>
</head>
<body></body>
</html>通过 HTTP 提供该目录,WebAssembly 的类型为 application/wasm,大多数 服务器默认如此。窗口填满 ID 为 mygo 的元素,没有该元素时填满页面; 之后打开的窗口覆盖先前的窗口。窗口大小由页面决定:大小、位置和标题栏 选项都无效,最后打开的窗口的标题就是页面的标题。
可用的功能
- 绘制。 帧以设备像素比用 WebGL 2 绘制,浏览器每一帧有变化时绘制 一次;特效,如 Liquid Glass,与桌面上一样 绘制。浏览器没有 WebGL 2 时,帧绘制在内存中,通过 2D canvas 显示。 WebGL 上下文丢失后,浏览器恢复它时即重新绘制。
- 文本来自浏览器:浏览器负责查找字体、为字体缺少的字形回退并进行 文字排版,与渲染页面相同:
system-ui就是系统字体,和页面里一样。 断行与文字段(bidi)的顺序在所有地方都与 text 包一致。文本不使用 亚像素抗锯齿绘制。 - 输入:指针(点击次数会被统计);滚轮和触控板;按键;输入法, 它们在一个位于光标处、不可见的文本区域中组合文本;以及剪贴板文本, 通过浏览器的复制、剪切和粘贴。在 Mac 上,视图的快捷键中 ⌘ 对应 Control,因为视图把浏览器当作非 macOS 的系统。
- 路由器。 窗口显示的第一个路由器跟随标签页的 历史记录,记录在 URL 的片段中,如
#/notes/42:浏览器的前进和后退 按钮在其页面之间导航,指向某个页面的链接或重新加载都会在那里打开 应用。 - 拖放到窗口上的文件:
DroppedFiles、FileDragOver和OnFileDrop与桌面上一样工作。浏览器不提供路径,因此后端在文件 落下时读取它们,并按自己的路径保存,如/mygo-drop/3/photo.png, 可以用os.Open、os.ReadFile、os.Stat和os.ReadDir读取; 最近 16 次拖放的文件会保留。 - 上下文菜单以页面上的 HTML 菜单形式显示。
- 深色模式、减弱动态效果和增强对比度跟随浏览器的设置,并随之变化。 页面可以在其根元素上用
data-mygo-theme="dark"或"light"自行 选择外观,正如包裹应用的框架为它指定自己的主题时那样(框架的prefers-color-scheme跟随浏览器,而不是它周围的页面)。 Dialog.Message用浏览器的alert和confirm询问,Shell.OpenExternal打开一个新标签页。
不可用的功能
网页窗口、应用和 Dock 菜单、托盘、通知、全局快捷键、文件对话框,以及 文件之外数据的拖放,在浏览器中没有对应的东西,调用时会报告这一点。 辅助技术目前还看不到内容。样式的 OpenType 特性中,canvas 只应用 kern。用 ui.RegisterFont 添加的字体需要其 family,浏览器加载后 即可绘制。剪贴板文本在粘贴时由系统带入:视图自己的粘贴命令粘贴的是 应用上次复制的内容。
体积
计数器示例的 WebAssembly 为 8.2 MB,gzip 压缩后 2.2 MB;本文档的预览 包含所有组件,为 9.8 MB(压缩后 2.6 MB)。浏览器构建会剔除 mygo 包中 服务于网页(它们并不显示网页)的部分:IPC、自定义 scheme 及其 HTTP、 TypeScript 生成器、更新器,以及它们所依赖的 JSON 和加密代码。它们的 API 仍然存在但什么都不做:Bind 不绑定任何东西,事件不会到达任何页面, Updater.Check 报告 ErrUpdatesDisabled。只有 Protocol.Handle、 HandleFunc 和 FileServer 缺失(它们接受 net/http 的类型),因此 使用它们的代码只适用于桌面(//go:build !js)。mygo build 为生产 构建设置的 mygo_noinspector 标签也会剔除原生 UI 检查器,约 350 KB。 为浏览器构建不会给桌面应用增加任何东西:浏览器的代码只存在于 js/wasm 构建中。
工作原理
Go 的主 goroutine 运行事件循环;浏览器的事件通过 JavaScript 调用的 函数传到它那里,这些函数会等待它处理,以便仍能阻止浏览器的默认行为。 架构指南的浏览器一节有 细节。