mcpField
W
wails

wails

github.com/spf13开发687149 次安装4 天前更新
代码仓库

关于 wails

为使用 Go 后端和平台 WebView 前端构建桌面应用提供 Wails 指南,覆盖稳定的 v2 与 Alpha 阶段的 v3。该技能强调先确认版本,避免混用不兼容的 API。

主要功能

  1. 01介绍 Go 与 Web 前端桌面应用
  2. 02分别说明 Wails v2 与 v3
  3. 03指导识别版本及对应 API
  4. 04涵盖绑定、事件与构建流程
  5. 05说明 v3 内嵌 MCP 服务能力

适用场景

  1. 01选择新项目使用的 Wails 版本
  2. 02排查 v2 与 v3 API 混用
  3. 03设计 Go 后端与前端绑定
  4. 04使用 Wails MCP 驱动应用测试

MCP 相关

指南说明 Wails v3 可通过设置 WAILS_MCP=1 在应用中嵌入 MCP 服务。MCP 客户端可借此控制窗口、检查 DOM 并调用绑定方法。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/spf13/go-skills --skill wails

安装后在 Claude Code 中输入/wails确认已加载。

附带文件.claude-plugin/plugin.json

详细介绍

Wails:使用 Go 构建桌面应用

Wails 使用 Go 后端和在平台 WebView 中渲染的 Web 前端(macOS/Linux 上为 WebKit,Windows 上为 WebView2)构建原生桌面应用。无需捆绑 Chromium——二进制文件只有几 MB,而不是几百 MB。

两个主要版本并存,API 互不兼容。 v2 稳定。v3(截至 2026 年年中)处于 alpha 后期:API 已相当稳定,也有生产应用在使用,但发布版本仍是 nightly v3.0.0-alpha2.x 标签,具体细节仍在变动。最常见的失败原因——尤其对大模型而言——是混用 v2 和 v3 代码。每个回答都必须纯粹使用 v2 或 v3。

步骤 0——检测版本(必须)

编写任何代码之前,先根据项目确定版本。不要根据用户的措辞猜测。

信号v2v3
go.mod 导入github.com/wailsapp/wails/v2github.com/wailsapp/wails/v3
CLIwails(wails dev、wails build)wails3(wails3 dev、wails3 build)
构建编排不透明,由 wails.json 驱动Taskfile.yml(go-task),透明
入口点wails.Run(&options.App{...})application.New(application.Options{...})
Go→JS 暴露方式Bind: []interface{}{app}Services: []application.Service{...}
Runtime 调用runtime.EventsEmit(ctx, ...),并存储上下文调用 app / window 上的方法——无需传递上下文
前端导入wailsjs/go/main/Appfrontend/bindings/<import-path>/<service>

**尚无代码的新项目:**如果用户需要稳定性且不希望频繁变动,默认使用 v2;如果用户接受 alpha 状态,则建议为新的长期应用使用 v3——其架构更完善(多窗口、服务、透明构建),并且是未来的发展方向。用一句话说明取舍,并在 go.mod 中固定确切的 alpha 版本。绝不要将 v3 描述为稳定版。

**如果现有代码中同时出现两列的 API,**这就是问题所在——先指出这一点,再进行其他操作。


Wails v2(稳定版)

标准 main.go
//go:embed all:frontend/dist
var assets embed.FS

func main() {
    app := NewApp()

    err := wails.Run(&options.App{
        Title:  "myapp",
        Width:  1024,
        Height: 768,
        AssetServer: &assetserver.Options{Assets: assets},
        OnStartup:  app.startup,
        Bind: []interface{}{app},
    })
    if err != nil {
        log.Fatal(err)
    }
}

embed 指令为 all:frontend/dist——必须使用 all: 前缀,才能包含 Vite 生成的以下划线开头的文件。

上下文捕获模式

v2 Runtime 中的所有功能都需要 OnStartup 传入的上下文。保存该上下文;这是每个 v2 应用的关键惯用模式:

type App struct {
    ctx context.Context
}

func (a *App) startup(ctx context.Context) {
    a.ctx = ctx // required for all runtime calls
}

func (a *App) OpenFile() (string, error) {
    return runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{})
}
  • 绝不要在 OnStartup 触发前调用 runtime.*——此时上下文尚不存在。这是典型的 v2 启动崩溃原因。
  • 此处的 runtime 指 github.com/wailsapp/wails/v2/pkg/runtime——用于窗口控制、对话框、事件、剪贴板和菜单。
绑定与事件
  • 绑定结构体上的导出方法会成为 wailsjs/go/main/App 下的异步 JS 函数。Go 的 (value, error) 返回值会转换为已兑现/已拒绝的 Promise。
  • Go→JS:使用 runtime.EventsEmit(a.ctx, "name", data);JS 端从 wailsjs/runtime 导入 EventsOn("name", cb)。
  • 绑定结构体应保持为精简的适配器——业务逻辑放在不导入 Wails 的独立包中(规则与 cobra-viper 技能中的 cmd/ 相同)。
v2 常见错误
  • 在启动前调用 Runtime 函数(上下文为 nil/无效)。
  • embed 指令缺少 all:——资源会在生产构建中被静默遗漏。
  • 编辑生成的 wailsjs/ 文件——每次运行 wails dev/wails build 时都会重新生成。
  • 按值绑定结构体(Bind: []interface{}{App{}})——应绑定指针,以便状态得以保留。

Wails v3(Alpha)

标准 main.go
//go:embed all:frontend/dist
var assets embed.FS

func main() {
    app := application.New(application.Options{
        Name: "myapp",
        Assets: application.AssetOptions{
            Handler: application.AssetFileServerFS(assets),
        },
        Services: []application.Service{
            application.NewService(NewGreetService()),
        },
    })

    app.Window.NewWithOptions(application.WebviewWindowOptions{
        Title: "myapp",
    })

    if err := app.Run(); err != nil { // blocks; must run on the main goroutine
        log.Fatal(err)
    }
}

使用 Manager API 风格——app.Window.NewWithOptions、app.Event.On、app.Menu.New()、app.SystemTray.New()。早期 alpha 版本使用扁平方法(app.NewWebviewWindowWithOptions、app.OnEvent);教程和大模型训练数据中充斥着这些旧方法。如果某个方法不存在,它很可能已移至某个 Manager 下——请查阅变更日志,而不是凭空编造。

服务:v3 绑定模型

服务取代了 v2 的 Bind。服务是普通结构体;导出的方法会被绑定,另外还有两个可选的生命周期方法可接入应用:

type NoteService struct {
    db *sql.DB
    mu sync.RWMutex
}

func (s *NoteService) ServiceStartup(ctx context.Context, opts application.ServiceOptions) error {
    // open resources, run migrations, start background goroutines governed by ctx
    return nil // returning error aborts app startup
}

func (s *NoteService) ServiceShutdown() error {
    return s.db.Close() // services shut down in reverse registration order
}

func (s *NoteService) Save(n Note) error { ... } // callable from JS
  • 服务是由所有窗口共享的单例——使用互斥锁保护可变状态。
  • 依赖通过普通构造函数传入(application.NewService(NewNoteService(db, logger)))——无需 DI 框架。
  • 服务可通过实现 http.Handler 提供 HTTP 服务,并使用 application.NewServiceWithOptions(svc, application.ServiceOptions{Route: "/files"}) 注册。
  • 与 v2 一样遵循精简原则:服务是适配器;领域逻辑放在不依赖 Wails 的包中,便于作为普通 Go 代码进行测试。
绑定、事件和窗口
  • 使用 wails3 generate bindings 生成前端绑定(wails3 dev 会自动运行)。从 frontend/bindings/<full-go-import-path>/<service> 导入,而不是从 wailsjs/ 导入。
  • 事件:app.Event.Emit("name", data) / app.Event.On("name", handler);操作系统级事件通过 app.Event.OnApplicationEvent(events.Common.ApplicationStarted, ...) 处理。可取消的钩子:window.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { e.Cancel() })——这是标准的“关闭前确认”模式。
  • 多窗口是 v3 的一等功能:可根据需要创建任意数量的 WebviewWindow;每个窗口都可独立配置。
构建系统

v3 构建由 go-task 通过 Taskfile.yml 编排——图标生成、清单和打包都是可见、可编辑的任务步骤,而不是黑箱。通过编辑任务进行自定义,不要与 CLI 较劲。平台打包命令:wails3 package(macOS 上生成 .app/dmg,Windows 上生成 NSIS 包,Linux 上生成 AppImage/deb)。

Agentic 额外优势:使用 WAILS_MCP=1 构建会嵌入 MCP 服务,让大模型 Agent(包括 Claude)能够操控正在运行的应用——控制窗口、检查 DOM、调用绑定方法——这对开发期间的自动化测试非常有用。

v3 Alpha 使用规范
  • 在 go.mod 中固定 alpha 版本,并谨慎升级,同时阅读变更日志(v3.wails.io/changelog)——nightly alpha 版本可能会重命名 API。
  • 如果 v3 API 调用编译失败且无法明显看出修复方法,请先查看当前文档再进行猜测——由于 alpha 版本的特性,训练数据会滞后。

版本混用迹象(发现即拒绝)

  • 在 v3 项目中使用 runtime.EventsEmit(ctx, ...) 或导入 pkg/runtime → 这是 v2 API;应使用 app.Event.Emit。
  • 在 v2 项目中使用 application.New(...) 或 pkg/application → 这是 v3 API;应使用 wails.Run(&options.App{...})。
  • v3 前端导入 wailsjs/go/...(应使用 frontend/bindings/...),或反之。
  • 在 v3 项目中运行 wails dev,或在 v2 项目中运行 wails3 dev。
  • 在 application.Options 中包含 Bind: 字段,或在 options.App 中包含 Services:——这些字段各自只属于对应的版本。

两个版本通用的原则

  • 前端输入不可信:绑定方法中的参数必须像 HTTP 处理器一样进行验证;绝不能根据原始前端字符串构建 shell 命令或文件路径。
  • 绑定方法应返回错误(错误会以消息形式成为 Promise 拒绝)——不要 panic,也不要吞掉错误。
  • 密钥保留在 Go 端;frontend/dist 中发布的任何内容都可被用户读取。
  • 绑定方法中的长时间运行任务会阻塞 JS Promise,但不会阻塞 UI——应发送进度事件,而不是让前端轮询。

评论

支持 Markdown