外观
插件
插件由两半组成,为网页添加一项功能:Go 服务,以及一个函数调用这些服务的 JavaScript 包。应用用 mygo.Use 使用 Go 那一半,并从 npm 导入 JavaScript 那一半。
官方插件
- Fetch:从 Go 发起 HTTP 请求的
fetch,不受 CORS 限制,可带任意请求头、流式请求体和取消。 - WebSocket:连接由 Go 建立的
WebSocket,握手时 可带请求头。 - SQLite:本地数据库、参数化查询与原子事务,使用以 Zig 编译的 SQLite C 引擎,无需 cgo。
- Watch:监视应用允许页面监视的目录中的文件变化。
- Updater:仿照 Sparkle 的更新窗口,检查更新并提示 安装。它全部是 Go,其窗口是一个网页,或者对原生 UI 应用来说是原生 UI。
- Terminal:面向原生 UI 的终端,一个基于 Ghostty 终端模拟器运行 shell 或任意程序的视图。它全部是 Go,附带一个由 CLI 放入 应用的本地库。
- Glass:为原生 UI 在所有平台上呈现 macOS 那样的 Liquid Glass,带有 macOS 的滚动边缘和背景模糊。它全部是 Go,带有自己的 着色器。
- Game:游戏在普通应用之外所需的东西,按需启用:固定 步长的游戏循环及其输入、摄像机,以及统一标准布局的游戏手柄。它全部是 Go。
- Loading:loading.dev 的 29 种加载指示器,用于原生 UI,外观与动态与浏览器中一致。它全部是 Go。
- Automation:一个套接字,另一个进程——端到端测试 运行器或智能体——通过它驱动正在运行的应用:它的窗口、窗口中原生 UI 的 元素、输入、菜单、页面中的脚本和截图。它全部是 Go,按需启用,并且不会 包含在发布构建中。
使用插件
在 App.Run 之前,用 mygo.Use 传入应用的插件:
go
import (
"github.com/egoist/mygo"
"github.com/egoist/mygo/plugins/fetch"
"github.com/egoist/mygo/plugins/websocket"
)
func main() {
mygo.Use(fetch.Plugin, websocket.Plugin)
// ...
}前端则导入它们的包:
sh
bun add @mygo-plugins/fetch @mygo-plugins/websocketts
import { fetch } from "@mygo-plugins/fetch";
import { WebSocket } from "@mygo-plugins/websocket";
const res = await fetch("https://api.example.com/me", {
headers: { authorization: `Bearer ${token}` },
});
const ws = new WebSocket("wss://api.example.com/live", [], {
headers: { authorization: `Bearer ${token}` },
});官方插件的 Plugin 变量使用默认选项,其 New 函数接受选项,例如 fetch 和 WebSocket 插件的 http.Client,以及决定页面可以发起哪些请求的 Allow 函数。各插件的页面列出了这些选项。
只使用插件的 JavaScript 包而没有其 Go 那一半,会失败并报错,提示调用 mygo.Use。
编写插件
Go 那一半是一个 mygo.Plugin:一个名称、一个其方法供页面调用的服务,以及 一个可选的 Setup,在应用使用它时运行:
go
package clock
// Plugin 让页面获取 Go 侧的时间。
var Plugin = mygo.Plugin{Name: "clock", Service: service{}}
type service struct{}
func (service) Now() time.Time { return time.Now() }该服务的绑定方式与 mygo.Bind 的那些相同,其方法遵循同样的规则(context、 channel、错误),但名称为 plugin:<name>,且不在生成的 TypeScript 客户端 之中。它的 JavaScript 包通过 mygo-runtime 的 call 来调用它,并把 mygo-runtime 列为 peer dependency,从而使用应用自带的那一份(同时列为 开发依赖,用于自身的构建和测试):
ts
import { call } from "mygo-runtime";
export const now = async () => new Date(await call<string>("plugin:clock.Now"));只有应用信任的页面才能调用插件,与每个绑定方法一样。当名称已被占用,或 服务的方法使用了无法传递到 JavaScript 的类型时,mygo.Use 会 panic,因此 错误会在启动时暴露。