用 Wails3 打造生产级桌面应用:MQTTW 开源案例拆解
1 为什么值得关注这个案例
做桌面工具,绕不开三个老问题:技术栈怎么选、工程怎么分层、跨平台怎么打包。Electron 生态成熟但体积和内存一直是痛点;Qt 能力强但开发成本和授权复杂;用原生 API 写三端又等于维护三套代码。
最近 GoFly 社区开源了 MQTTW——一款基于 Wails3 + Go + Vue3 构建的 MQTT 调试压测一体化桌面客户端(Apache-2.0)。它不只是个好用的 MQTT 工具,更是一份可以直接参考的 Wails3 生产级工程样板:全面支持 MQTT 3.1 / 3.1.1 / 5.0,集连接调试、消息收发、多连接管理、大规模客户端压测于一体,当前版本 v1.0.3,Windows / macOS / Linux 三端可跑。
这篇从技术选型、目录结构、核心代码三个角度拆解它,写给正在做桌面应用选型的技术员和软件公司。
2 技术选型:桌面应用的三条路线
2.1 三条路线对比
| 对比维度 | Electron | Tauri | Wails3 |
|---|---|---|---|
| 运行时 | 捆绑 Chromium + Node.js | 系统 WebView + Rust 后端 | 系统 WebView + Go 后端 |
| 包体积 | 普遍 100MB 起 | 较小(几 MB 到十几 MB) | 单二进制约 10MB 量级 |
| 内存占用 | 高 | 低 | 低 |
| 后端语言 | Node.js | Rust | Go |
| 前端 | 任意 Web 技术栈 | 任意 Web 技术栈 | 任意 Web 技术栈 |
| 跨平台 | 三端 | 三端 | 三端(Wails3 还支持移动端) |
| 适合场景 | 复杂 Web 生态复用 | 追求轻量 + Rust 团队 | 追求轻量 + Go 团队 |
2.2 为什么选 Wails3
对 Go 技术栈的团队来说,Wails3 的优势非常直接:
- 后端用 Go,前端随便选:应用逻辑全在 Go 侧,界面用 Vue / React / Svelte 都行,不引入浏览器运行时;
- 原生 WebView 渲染:界面跑在系统自带 WebView 上,启动快、内存占用低,打包出来接近原生应用体积;
- 自动生成类型安全 bindings:Go 服务注册后,
wails3 dev/wails3 build会自动在frontend/bindings/生成 TypeScript SDK,前端像调本地 API 一样调 Go 方法,前后端契约天然一致; - 开发体验好:Go 改动自动重建重启,前端改动热重载,调试效率高。
3 MQTTW:项目概览
3.1 项目定位与技术栈
MQTTW 面向物联网(IoT)开发、Broker 联调验证与性能压测场景。官方公开的技术栈清单:
- 桌面框架:Wails3 v3.0.0-beta.9,Go 1.25+
- 前端:Vue 3 + TypeScript + Vite + Arco Design Vue + Pinia
- 能力组件:ECharts(压测实时曲线)、Monaco Editor(消息/脚本编辑)
- 存储:SQLite(纯 Go 驱动,无 CGO)
- 数据层:GORM + GORM Gen;国际化 vue-i18n;内置 MCP 服务
3.2 核心功能一览
- 图形化连接 Broker,自动识别协议版本,支持 TLS/SSL、证书、自动重连;
- 多连接分组树形管理,连接配置持久化到 SQLite,一键复用;
- 订阅多主题 + JSON 自动高亮,消息实时推送并异步入库,可回溯查询;
- 发布支持 JSON / Plaintext / Base64 / Hex,QoS 0/1/2、Retain,完整 MQTT 5 发布属性面板;
- 独立压测模块:数千至数万客户端并发,实时输出连接成功率、收发速率与 P50/P95/P99 延迟,ECharts 曲线 + CSV 导出。
4 目录结构:一个生产级工程的拆解
MQTTW 后端按 dao / service / mqttclient / stress 分层,前端用 Vue3 组合式 API。以 Wails3 官方工程结构为基线,典型布局如下:
mqttw/
├── main.go # 应用入口:Wails 实例 + 服务注册
├── internal/
│ ├── dao/ # 数据访问层:SQLite 读写(连接配置、消息记录)
│ ├── service/ # 业务服务层:对外暴露给前端的 Go 方法
│ ├── mqttclient/ # MQTT 客户端封装:连接、订阅、发布、自动重连
│ └── stress/ # 压测模块:批量建连、指标采集与统计
├── frontend/ # Vue3 + TS 前端
│ ├── src/
│ │ ├── views/ # 页面:连接、调试、压测、设置
│ │ ├── stores/ # Pinia 状态
│ │ └── bindings/ # wails3 自动生成的类型安全 SDK(勿手改)
│ └── vite.config.ts
├── build/ # 各平台打包配置
└── Taskfile.yml # 构建任务
各层职责:
| 目录 | 职责 | 关键点 |
|---|---|---|
| dao | 数据持久化 | SQLite 纯 Go 驱动,跨平台编译无 CGO 负担 |
| service | 前端可调用的业务接口 | 导出方法即接口,类型即契约 |
| mqttclient | MQTT 协议封装 | 多版本协议、自动重连、消息事件回调 |
| stress | 压测执行与统计 | 并发建连、速率控制、P50/P95/P99 计算 |
5 核心代码:Wails3 的典型写法
以下代码为 Wails3 官方标准写法 + MQTT 通用实现示例,可直接迁移到自己的项目。
5.1 应用入口与服务注册(main.go)
package main
import (
"github.com/wailsapp/wails/v3/pkg/application"
)
func main() {
err := application.New(application.Options{
Name: "MQTTW",
Description: "MQTT 调试与压测一体化客户端",
Services: []application.Service{
application.NewService(&MqttService{}), // MQTT 连接/订阅/发布
application.NewService(&StressService{}), // 压测服务
},
}).Run()
if err != nil {
panic(err)
}
}
5.2 业务服务:导出方法即接口(service/mqtt.go)
package main
import (
"fmt"
"time"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
type MqttService struct {
client mqtt.Client
}
// Connect 建立 MQTT 连接,前端可直接调用
func (s *MqttService) Connect(host string, port int, clientID string) (bool, error) {
opts := mqtt.NewClientOptions().
AddBroker(fmt.Sprintf("tcp://%s:%d", host, port)).
SetClientID(clientID).
SetAutoReconnect(true).
SetConnectTimeout(5 * time.Second)
client := mqtt.NewClient(opts)
token := client.Connect()
if token.Wait() && token.Error() != nil {
return false, token.Error()
}
s.client = client
return true, nil
}
// Publish 发布消息,QoS 由前端传入
func (s *MqttService) Publish(topic string, qos byte, payload string) error {
token := s.client.Publish(topic, qos, false, payload)
token.Wait()
return token.Error()
}
5.3 前端调用 Go 方法(Vue3 + 自动生成的 bindings)
import { MqttService } from "../bindings/mqttw";
async function connect() {
const ok = await MqttService.Connect("192.168.1.10", 1883, "mqttw_demo");
if (ok) {
// 连接成功,继续订阅、发布
}
}
5.4 压测并发模型示意(stress/stress.go)
package main
import (
"sync"
"sync/atomic"
)
type StressService struct{}
// RunStress 批量创建客户端并发压测,连接速率可控
func (s *StressService) RunStress(host string, port int, count int) map[string]any {
var (
success atomic.Int64
failed atomic.Int64
wg sync.WaitGroup
)
for i := 0; i < count; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// 每个 goroutine 创建一个客户端并连接
// 记录耗时,汇入 P50/P95/P99 统计
ok := connectOne(fmt.Sprintf("stress-%d", id))
if ok {
success.Add(1)
} else {
failed.Add(1)
}
}(i)
}
wg.Wait()
return map[string]any{
"total": count,
"success": success.Load(),
"failed": failed.Load(),
}
}
要点:服务导出方法 = 前端接口,Go 的并发能力(goroutine)直接服务于压测这类重 IO 场景,前端只管展示实时指标。
6 对技术团队与软件公司的价值
- 可商用、可二次开发:Apache-2.0 协议,代码完全开放,可直接在其上定制自己的 MQTT 工具;
- 工程规范可借鉴:dao / service / mqttclient / stress 分层清晰,适合作为团队内部 Wails3 项目规范基线;
- 跨平台交付省心:SQLite 纯 Go 无 CGO,交叉编译少踩环境坑;一套代码出 NSIS/MSIX、dmg、deb/AppImage;
- 配套生态完整:官方配套 GMQT Broker(Go 编写、内嵌数据库),支持独立部署,也提供免费在线服务 gmqt.goflys.cn(默认账号 admin / admin,支持 TCP / WS / SSL / WSS),调试压测开箱即用;
- 学习价值高:托盘、全局快捷键、国际化、数据持久化等桌面能力在项目里都有完整实现,是 Wails3 入门到实战的现成教材。
7 如何开始
- 官网:goflys.cn/mqttw
- GitHub:github.com/huanglishi/mqttw
- Gitee:gitee.com/huang_li_shi_admin/mqttw
- 下载:v1.0.3 提供 Windows(NSIS / MSIX)、macOS(dmg)、Linux(deb / AppImage)安装包;也可以拉源码自行构建:
wails3 dev开发、wails3 package出包。
如果你在选型桌面应用技术栈,或在找一款能压测的 MQTT 客户端,不妨下载试试。顺手点个 Star,也是对这个开源项目的支持。


本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu
推荐文章: