用 Wails3 打造生产级桌面应用:MQTTW 开源案例拆解

AI摘要
该内容为技术分享类文章,介绍基于 Wails3 + Go + Vue3 构建的开源 MQTT 调试压测桌面客户端 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 如何开始

如果你在选型桌面应用技术栈,或在找一款能压测的 MQTT 客户端,不妨下载试试。顺手点个 Star,也是对这个开源项目的支持。


本作品采用《CC 协议》,转载必须注明作者和本文链接
GoFly全栈开发社区
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
22
粉丝
5
喜欢
12
收藏
14
排名:1215
访问:3725
私信
所有博文
社区赞助商