本文永久链接 – https://tonybai.com/2026/08/04/wails-v3-go-desktop-framework
大家好,我是Tony Bai。
【导读】
如果你用 Go 写过桌面应用,大概率听过 Wails——它让 Go 开发者可以用 HTML、CSS、JS 这套最熟悉的前端工具链,调用系统原生 WebView,做出媲美 Electron 的跨平台桌面应用,却不必打包一整个 Chromium。
北京时间 2026 年 8 月 2 日,Wails 团队正式发布了 Wails v3 Beta。这不是一次小版本迭代,而是自 2023 年 1 月立项以来,历时三年多打磨出的一次架构级重写:应用不再只有一个隐藏在配置项背后的 Run() 函数,而是拥有了显式的应用、窗口、服务对象模型;前端绑定不再依赖“先编译再反射”的旧套路,而是通过静态源码分析直接生成;构建系统也从一个黑盒命令,变成了可读、可改、可调试的 Taskfile。
这篇文章将带你梳理 Wails v3 Beta 到底带来了什么、为什么要做这么大的重构,以及如何用几行代码跑起你的第一个 v3 应用。
【文章要点】
- Wails v3 Beta 于 2026 年 8 月 2 日正式发布,桌面端 API 已稳定,已有团队在生产环境使用,但仍建议在正式迁移前充分测试;
- 核心变化有五个:显式的应用生命周期 API、原生多窗口支持、基于静态分析的 Go 服务与自动生成绑定、可检查可扩展的 Taskfile 构建系统、更扎实的跨平台基线(含实验性 iOS / Android 支持);
- 从 v2 迁移到 v3 是一次真正的移植工作,官方提供了详细的迁移指南和功能对照表,而非简单的版本号升级;
- Wails 项目的 GitHub Star 数从 2021 年的约 4000,涨到 2022 年 v2 发布时的约 10300,如今已超过 35000;
- 项目从“完美主义式”发版策略,转向了 2024 年底开始的“每日发版”策略,加速了 Beta 的到来;
- 安装方式很简单:
go install github.com/wailsapp/wails/v3/cmd/wails3@latest,然后wails3 setup和wails3 init即可上手。

Wails 是什么
对没接触过 Wails 的读者简单科普一下:Wails 让 Go 开发者可以用自己已经很熟悉的 Web 前端技术栈(HTML/CSS/JS,以及 Vue、React、Svelte 等框架)来写桌面应用界面,后端逻辑全部用 Go 编写,两者之间通过自动生成的绑定互相调用。
和 Electron 最大的不同在于,Wails 调用的是操作系统自带的原生 WebView 组件(macOS 上是 WKWebView,Windows 上是 WebView2,Linux 上是 WebKitGTK),而不是把一整个 Chromium 内核塞进安装包里。这意味着同样的应用,Wails 打出来的包体积要小得多,启动速度也更快。
Wails v2 于 2022 年 9 月 22 日发布,带来了基于 Vite 的热更新开发体验、窗口与菜单管理、微软 WebView2 组件、Go 结构体到 TypeScript 类型的自动生成、NSIS 安装包制作、代码混淆构建等一整套能力,是目前生产环境中依旧稳定可靠的版本。
为什么要做 v3:v2 的三大痛点
Lea Anthony 在 2023 年 1 月发布的规划文章《The Road to Wails v3》里,坦诚地列出了 v2 架构里拖累项目的三个问题。
第一,应用 API 太“声明式”,多窗口成了硬伤
v2 的应用层 API 事实上只有一个函数——wails.Run(),把一大堆配置项塞进去,框架帮你把一切都做好。这种写法上手简单,但也意味着开发者拿不到主窗口的句柄,想直接操作窗口只能求助另一套“运行时 API”(Runtime API),而这套 API 又必须传入一个 context.Context 才能工作,新手极容易踩坑。更关键的是,Runtime API 从设计之初就是为单窗口场景服务的,而“支持多窗口”恰恰是 GitHub 上呼声最高的功能请求。
第二,绑定生成靠“先编译、后反射”的取巧办法
v2 生成前端可调用绑定的方式,是先用特殊标志编译出一个二进制文件,再运行它、用反射分析出到底绑定了哪些方法——这是一个先有鸡还是先有蛋的怪圈:不生成绑定就编译不出完整应用,不编译应用又生成不出绑定。
第三,构建系统是个黑盒
执行一次 wails build,背后要做的事情多达十几步:编译后端二进制、生成绑定、安装前端依赖、构建前端资源、处理图标、编译最终二进制、macOS 下用 lipo 合并双架构胖二进制、UPX 压缩、打包应用包或 NSIS 安装包……全部逻辑封装在框架内部,想自定义某一步几乎无从下手,出了问题也很难调试。
这三点,构成了 v3 重写的直接动机。
v3 Beta 到底新在哪:五大变化逐一拆解
1. 显式的应用生命周期 API
v3 用一套显式的对象模型,取代了 v2 那个包罗万象的 wails.Run(...)。现在你需要创建一个应用实例、注册服务、创建窗口,然后直接对这些对象进行操作——窗口相关的行为归窗口对象管,应用级别的行为归应用对象管,不再需要到处传递隐式的 Context。
这种模式对多窗口应用天然友好,也更符合大型代码库的可测试性和可维护性诉求。官方在文章中特别提到,Alpha 阶段的开发者对这种显式模型反馈非常积极——代码更容易读懂,归属关系更清晰,复杂应用也有了在框架内“自然生长”的空间,而不用和框架“打架”。
2. 原生多窗口支持
多窗口不再是workaround,而是 v3 的核心能力之一。窗口拥有独立的生命周期,可以在运行时随意创建、管理、关闭,这为编辑器、检查器、偏好设置面板、工具窗口等一切需要多个独立界面的桌面应用铺平了道路。
3. Go 服务与静态分析生成的绑定
v3 用“服务(Service)”取代了 v2 那种松散的绑定模式。业务逻辑依然是普通的 Go 代码,但服务和前端之间的边界变得非常清晰:生成的绑定会按照应用和服务的结构组织起来,方便查找和使用。
更关键的是绑定生成方式的变化:v3 改用静态源码分析,而不是运行已编译程序再靠反射“猜”绑定关系。这不仅解决了 v2 那种先有鸡还是先有蛋的怪圈,还带来一个额外好处——生成器现在能够保留开发者写在代码里的信息,比如注释和有意义的参数名,因此生成出来的前端 TypeScript API 更加丰富、可读性更强。
值得一提的是,服务现在还可以捆绑自己的前端资源和脚本,也就是说一个能力可以同时拥有自己的后端 API、前端 JS/UI,以及和宿主应用的集成点。这为将来的 Wails 插件生态打开了空间:装一个插件、挂载它的服务,就能直接用上一整套开箱即用的功能,而不必再手动拼装一堆零散的绑定和前端依赖。
官方明确说明,通用插件系统本身并不在这次 Beta 范围内,但 v3 的架构已经让这个方向变得可行——这在 v2 的绑定模型下是做不到的。
4. 可检查、可扩展的构建系统
v3 把构建流程彻底摊开在明面上。项目采用统一的目录结构,配合基于 Task 的 Taskfile.yml 构建配置——熟悉 Makefile 的开发者会很快上手。日常仍然可以用 wails3 build 一键完成所有事情,但如果你想定制构建流程,直接编辑 Taskfile.yml 就行,图标生成、压缩、打包这些原子操作依然由 Wails CLI 内置提供,不需要额外装一堆外部工具。
5. 更扎实的跨平台基线
Beta 版本支持 Windows(amd64/arm64)、macOS(Intel/Apple Silicon)、Linux(amd64/arm64)。Linux 端默认技术栈是 GTK4 + WebKitGTK 6.0,GTK3 会作为遗留选项在整个 v3.0 系列里继续保留。此外,v3 还带来了实验性的 iOS 和 Android 支持,可以探索尝鲜,但暂不在桌面 Beta 的兼容性承诺范围内。
除此之外,这次发布也补上了不少“日常体验”层面的工作:更完善的平台行为、更强大的窗口模型、更清晰的诊断信息,以及带校验和与来源证明(provenance)的发布产物。
从“完美主义”到“每日发版”:一段坦诚的开发历程
v3 的第一个 Alpha Tag 打在 2023 年 1 月 18 日,到 2026 年 8 月的 Beta 发布,走了三年半。这中间发生了什么?
2024 年 12 月,团队发布了 Alpha 10,同时公开做了一次坦诚的复盘:早期团队陷入了“完美主义陷阱”——总想在每次发版前把每一个 bug 都修完、每一个功能都打磨到位,但软件从来不存在“完全无 bug”的状态,一味等待只会拖慢改进落地的速度。
于是团队从 Alpha 10 开始转向每日发版策略:当天合并的改动,当天就会发布出去。
这么做的好处是明摆着的——bug 修复和新功能能更快触达用户、反馈循环更短、Beta 之路走得更快、整个开发过程也更透明。
团队同时开放了 Alpha 阶段的 bug 报告渠道,把标记为 “Ready for Work” 的 issue 开放给社区贡献者认领,并特别强调:测试 PR 是当前最有价值的贡献方式之一,不需要多深的代码功底,光是在不同环境下验证改动能不能正常工作,就已经很有价值。
这次“不装了”式的坦诚,也延续到了 Beta 发布文章里。作者提到,Wails 的 Star 数从 2021 年 v2 首个 Beta 发布时的约 4000,涨到 2022 年 v2 正式发布时的约 10300,如今已经超过 35000。
用户体量的增长意味着更多人依赖发版决策、更多贡献者需要清晰的参与路径,好的项目治理不再只是“做完下一个功能”那么简单。作者坦承自己在过去没能及时跟上项目增长所要求的流程演进,并给出了具体的改进措施:明确的 Beta / RC / GA 里程碑、更清晰的兼容性承诺、更新后的安全策略,以及一套用于评审公开行为变更和新能力的 WEP(Wails Enhancement Proposal)流程。
上手实战:五分钟跑起你的第一个 Wails v3 应用
说了这么多架构层面的变化,不如直接上手感受一下。以下步骤基于官方 Beta 文档,环境要求 Go 1.25 及以上。
1. 安装 CLI 并跑一次环境体检
go install github.com/wailsapp/wails/v3/cmd/wails3@latest
wails3 setup
wails3 setup 会检查本地开发环境,并引导你配置 Wails 所需的各项依赖(比如 Linux 下的 WebKitGTK)。

2. 初始化一个项目
wails3 init -n myapp
cd myapp
wails3 dev
默认模板是 Vanilla + Vite(HTML/CSS/TypeScript)。如果你更喜欢 React、Vue、Svelte,可以加上 -t react、-t vue、-t svelte 参数;纯 JavaScript 版本用 -t vanilla-js 或 -t react-js。想看全部可选模板,执行 wails3 init -l。
初始化完成后目录大致长这样:
myapp/
├── README.md
├── Taskfile.yml # 构建任务定义
├── build/ # 构建相关配置
│ ├── Taskfile.yml
│ ├── android/
│ ├── appicon.icon/
│ ├── appicon.png
│ ├── config.yml
│ ├── darwin/
│ ├── docker/
│ ├── ios/
│ ├── linux/
│ └── windows/
├── frontend/ # 前端代码
│ ├── Inter\ Font\ License.txt
│ ├── index.html
│ ├── package.json
│ ├── public/
│ ├── src/
│ ├── tsconfig.json
│ └── vite.config.ts
├── go.mod
├── go.sum
├── greetservice.go # 一个示例服务
└── main.go # 应用入口
11 directories, 14 files
运行wails3 dev后,wails会下载依赖、构建并运行一个脚手架程序:
$wails3 dev
Wails v3.0.0-beta.2 › Build
task: [darwin:common:go:mod:tidy] go mod tidy
task: [darwin:common:generate:icons] wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin
task: [darwin:common:generate:bindings] wails3 generate bindings -f '-buildvcs=false -gcflags=all="-l"' -clean=true -ts -i
Wails v3.0.0-beta.2 › Generate Bindings
▀ Loading packages... (0s)task: [darwin:common:install:frontend:deps:npm] npm install
INFO Processed: 238 Packages, 1 Service, 1 Method, 0 Enums, 0 Models, 1 Event in 39.01382603s.
INFO Output directory: /Users/tonybai/test/go/wails-v3/myapp/frontend/bindings
added 24 packages in 41s
9 packages are looking for funding
run `npm fund` for details
task: [darwin:common:frontend:run:npm] npm run build:dev -q
> frontend@0.0.0 build:dev
> vite build --minify false --mode development
vite v8.2.0 building client environment for development...
✓ 35 modules transformed.
computing gzip size...
dist/index.html 3.20 kB │ gzip: 1.23 kB
dist/assets/index-Bgw7f08b.js 89.57 kB │ gzip: 23.05 kB
✓ built in 73ms
task: [darwin:build:native] go build -buildvcs=false -gcflags=all="-l" -o "bin/myapp"
Need documentation? Run: wails3 docs
♥ If Wails is useful to you or your company, please consider sponsoring the project: wails3 sponsor
task: [darwin:run] mkdir -p "bin/myapp.dev.app/Contents/MacOS"
task: [darwin:run] mkdir -p "bin/myapp.dev.app/Contents/Resources"
task: [darwin:run] cp build/darwin/icons.icns "bin/myapp.dev.app/Contents/Resources"
task: [darwin:run] if [ -f build/darwin/Assets.car ]; then
cp build/darwin/Assets.car "bin/myapp.dev.app/Contents/Resources"
fi
task: [darwin:run] cp "bin/myapp" "bin/myapp.dev.app/Contents/MacOS"
task: [darwin:run] cp "build/darwin/Info.dev.plist" "bin/myapp.dev.app/Contents/Info.plist"
task: [darwin:run] codesign --force --deep --sign - "bin/myapp.dev.app"
task: [darwin:run] "bin/myapp.dev.app/Contents/MacOS/myapp"
task: [common:install:frontend:deps:npm] npm install
added 1 package in 1s
9 packages are looking for funding
run `npm fund` for details
task: [common:frontend:dev:npm] npm run dev -- --port 9245 --strictPort
> frontend@0.0.0 dev
> vite --port 9245 --strictPort
2:49PM INF Build Info: Wails=v3.0.0-beta.2 Compiler=go1.26.0 DefaultGODEBUG=cryptocustomrand=1,tlssecpmlkem=0,urlstrictcolons=0 CGO_CPPFLAGS= CGO_CXXFLAGS= -compiler=gc CGO_ENABLED=1 CGO_CFLAGS=-mmacosx-version-min=12.0 CGO_LDFLAGS=-mmacosx-version-min=12.0 GOARCH=amd64 GOOS=darwin GOAMD64=v1 -buildmode=exe -gcflags=all=-l
2:49PM INF Platform Info: ID=24G231 Name=MacOS Version=15.7.1 Branding=Sequoia
2:49PM INF AssetServer Info: middleware=true handler=true devServerURL=http://localhost:9245
2:49PM INF Waiting for frontend dev server to start... url=http://localhost:9245
2:49PM INF Retrying...
VITE v8.2.0 ready in 2049 ms
➜ Local: http://127.0.0.1:9245/
2:49PM INF Retrying...
2:49PM INF Connected to frontend dev server!
之后就会看到一个如下的页面出现在你眼前:

输入你要Greeting的名字,程序便可以正常运作。
3. 感受一下“服务即后端 API”
打开 greetservice.go,可以看到一个再普通不过的 Go 结构体:
package main
type GreetService struct{}
func (g *GreetService) Greet(name string) string {
return "Hello " + name + "!"
}
任何导出的方法(首字母大写)都会被静态分析器扫描到,自动生成对应的 TypeScript 绑定。在 main.go 里,你只需要把服务注册进应用配置:
package main
import (
"embed"
"log"
"time"
"github.com/wailsapp/wails/v3/pkg/application"
)
// Wails uses Go's `embed` package to embed the frontend files into the binary.
// Any files in the frontend/dist folder will be embedded into the binary and
// made available to the frontend.
// See https://pkg.go.dev/embed for more information.
//go:embed all:frontend/dist
var assets embed.FS
func init() {
// Register a custom event whose associated data type is string.
// This is not required, but the binding generator will pick up registered events
// and provide a strongly typed JS/TS API for them.
application.RegisterEvent[string]("time")
}
// main function serves as the application's entry point. It initializes the application, creates a window,
// and starts a goroutine that emits a time-based event every second. It subsequently runs the application and
// logs any error that might occur.
func main() {
// Create a new Wails application by providing the necessary options.
// Variables 'Name' and 'Description' are for application metadata.
// 'Assets' configures the asset server with the 'FS' variable pointing to the frontend files.
// 'Bind' is a list of Go struct instances. The frontend has access to the methods of these instances.
// 'Mac' options tailor the application when running an macOS.
app := application.New(application.Options{
Name: "myapp",
Description: "A demo of using raw HTML & CSS",
Services: []application.Service{
application.NewService(&GreetService{}), // Bind服务
},
Assets: application.AssetOptions{
Handler: application.AssetFileServerFS(assets),
},
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: true,
},
})
// Create a new window with the necessary options.
// 'Title' is the title of the window.
// 'Mac' options tailor the window when running on macOS.
// 'BackgroundColour' is the background colour of the window.
// 'URL' is the URL that will be loaded into the webview.
app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "Window 1",
// Window sized to the golden ratio (1000 / 618 ≈ 1.618).
Width: 1000,
Height: 618,
Mac: application.MacWindow{
InvisibleTitleBarHeight: 50,
Backdrop: application.MacBackdropTranslucent,
TitleBar: application.MacTitleBarHiddenInset,
},
BackgroundColour: application.NewRGB(6, 7, 15),
URL: "/",
})
// Create a goroutine that emits an event containing the current time every second.
// The frontend can listen to this event and update the UI accordingly.
go func() {
for {
now := time.Now().Format(time.RFC1123)
app.Event.Emit("time", now)
time.Sleep(time.Second)
}
}()
// Run the application. This blocks until the application has been exited.
err := app.Run()
// If an error occurred while running the application, log it and exit.
if err != nil {
log.Fatal(err)
}
}
前端这边,直接从自动生成的绑定里导入服务,像调用本地异步函数一样调用 Go 方法即可(下面代码已做了简化):
import { GreetService } from "../bindings/changeme";
window.greet = async () => {
const name = document.getElementById("name").value;
if (!name) return;
try {
const result = await GreetService.Greet(name);
document.getElementById("result").innerText = result;
} catch (err) {
console.error(err);
}
};
执行 wails3 dev 后,Go 代码的改动会自动触发重新编译并重启应用,前端代码的改动则直接热更新,不需要重启——这套开发体验和 v2 保持了一致的顺滑。
4. 加个多窗口试试
如果想直观感受一下 v3 引以为傲的多窗口能力,可以在 main.go 里再开一个窗口,并绑定关闭事件:
package main
import (
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/events"
)
func main() {
app := application.New(application.Options{Name: "MultiWindowDemo"})
mainWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "主窗口",
URL: "/",
})
mainWindow.OnWindowEvent(events.Common.WindowClosing, func(e *application.WindowEvent) {
app.Quit()
})
inspector := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "检查器",
Width: 480, Height: 640,
URL: "/inspector.html",
})
_ = inspector
app.Run()
}
两个窗口各自拥有独立的生命周期,互不依赖 Context 传递——这正是 v3 想解决的核心痛点之一。

5. 打包上线
wails3 build
会依次完成 Go 代码优化编译、前端资源生产构建(压缩)、生成对应平台的原生可执行文件,产物默认放在 bin/ 目录下。想自定义打包细节,直接改 Taskfile.yml 里对应的 task 即可。
从 v2 迁移到 v3,该注意什么
需要提醒的是:v3 是一次大版本升级,迁移是一次真正的移植工作,而不是改个 import 路径那么简单。 主要涉及的概念性变化包括:
- 应用与窗口的生命周期模型;
- 用“服务”取代了绑定到 Context 上的旧式绑定;
- 直接的应用 / 窗口 API 取代了 v2 的 Runtime 包;
- 前端绑定需要重新生成。
官方发布了详细的 v2 到 v3 迁移指南,里面包含功能对照表和测试清单,是目前 Beta 阶段官方支持的迁移路径。团队也明确建议:不要指望任何 v2 项目能“无脑转码”成功,一定要逐个测试、有意识地移植 Runtime 调用,并且在新应用真正就绪之前,让 v2 版本继续保留在生产环境中。
值得关注的是,官方还透露正在评估一个实验性的迁移辅助工具,但目前尚未包含在 Beta 里,团队表示会先用真实的 v2 项目验证充分之后,才会正式推荐使用。
另外一个细节是,Beta 阶段的官方文档只维护英文版本作为唯一可信源,暂不接受翻译 PR——要等 API 和工作流最终稳定之后,翻译工作才会重新启动,避免译者跟着文档反复返工。
小结
Wails v3 目前仍是 Beta,而非最终的 3.0 正式版:桌面端 API 已经稳定,也已经有团队在生产环境中使用,但官方仍然建议在正式切换前做充分测试。Wails v2 依旧是当前的稳定版本,会继续接收修复更新,短期内并不会被“抛弃”。
对于 Go 语言的桌面应用开发者来说,v3 带来的显式对象模型、原生多窗口、静态分析绑定和透明构建系统,几乎是针对 v2 时代最常被吐槽的几个点做的定向修复,方向感很强。如果你之前因为“不支持多窗口”、“Runtime API 太绕”而对 Wails 望而却步,现在或许是重新审视它的好时机。
想尝鲜的开发者,现在就可以执行:
go install github.com/wailsapp/wails/v3/cmd/wails3@latest
wails3 setup
wails3 init
如果在使用中遇到可复现的 bug,官方希望你附上 wails3 doctor 的输出和一个最小复现示例;如果你想提议新能力或者公开行为的变更,官方建议直接发起一个 WEP 草案 PR,而不是简单开一个 feature request issue。
参考链接:
- Wails v3 Beta 发布博客:https://v3.wails.io/blog/wails-v3-beta/
- Alpha 10 与每日发版策略:https://v3.wails.io/blog/2024-12-03-alpha10-and-new-release-strategy/
- 通往 Wails v3 之路(架构规划原文):https://v3.wails.io/blog/the-road-to-wails-v3/
- 官方文档:https://v3.wails.io/
- v2 到 v3 迁移指南:https://v3.wails.io/migration/v2-to-v3/
- GitHub 仓库:https://github.com/wailsapp/wails
(本文相关代码示例基于 Wails v3 官方文档整理,运行前请确保本机已安装 Go 1.25 及以上版本,并根据所在平台完成 wails3 setup 环境检查。)
还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 《从0 开始构建 Agent Harness》 将带你:
- 抛弃臃肿框架,回归“驾驭工程 (Harness Engineering)”的第一性原理
- 用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等,复刻极简OpenClaw
- 构建坚不可摧的 Safety Middleware 与飞书人工审批防线
- 在底层实现 Token 成本审计、链路追踪与自动化跑分评估
- 从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”
扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。

你的Go技能,是否也卡在了“熟练”到“精通”的瓶颈期?
- 想写出更地道、更健壮的Go代码,却总在细节上踩坑?
- 渴望提升软件设计能力,驾驭复杂Go项目却缺乏章法?
- 想打造生产级的Go服务,却在工程化实践中屡屡受挫?
继《Go语言第一课》后,我的《Go语言进阶课》终于在极客时间与大家见面了!
我的全新极客时间专栏 《Tony Bai·Go语言进阶课》就是为这样的你量身打造!30+讲硬核内容,带你夯实语法认知,提升设计思维,锻造工程实践能力,更有实战项目串讲。
目标只有一个:助你完成从“Go熟练工”到“Go专家”的蜕变! 现在就加入,让你的Go技能再上一个新台阶!

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。
