Wails + Vue3 构建现代桌面 UI 框架——基于 Go 的跨平台桌面应用实战(含源码案例)

264 阅读7分钟

很多刚接触 Go 的朋友都会有这样的困惑:

“Go 这么强大,但为什么没有官方的桌面 GUI 方案?”
“我想做个桌面工具,要选什么框架?”

确实,Go 官方从未把桌面开发当作核心路线,也完全没有提供 GUI 标准库。这就导致 Go 想做客户端应用时,往往不得不依赖第三方解决方案。

而这些方案,要么太臃肿,要么太硬核:

  • Electron:开发简单,但打包出来一个上百 MB 的应用,谁用谁心痛
  • Qt / GTK:跨平台强大,但学习成本极高,绑定也不够自然
  • 传统 WebView 框架:能跑,但生态差、性能堪忧

直到近几年,Go 生态真正出现了两位“能打”的选手:

  • Fyne —— 类 Flutter 的“纯 Go UI 框架”,想写纯后端式桌面开发,它很适合,团队没有前端的优选方案;
  • Wails —— 类 Tauri / Electron 的模式,用 HTML + JS + CSS 做界面,用 Go 做逻辑,前后端分离,找专业的人做专业的事,后端人员再不用因为界面丑而被客户嫌弃了。

更重要的是:

谁说桌面应用就不能前后端分离?
谁说 Go 只能做后端?
Wails 2 把这个多年的困境彻底解决了。

它不仅能把 Vue / React / Svelte 等现代前端框架无缝嵌入桌面窗口,还提供了优雅的 Go ↔ JS 通信机制,让你可以:

  • 用 Vue3 写界面
  • 用 Go 写业务逻辑
  • 像开发 Web 应用一样开发桌面应用
  • 最终产物比 Electron 轻几十倍

这让 Go + Wails 成为当下最具潜力的桌面应用组合之一。

Wails 2 出现,将 Go 与前端技术栈(Vue/React/Svelte)完美串联——让你用:

  • Go 写逻辑和系统 API
  • Vue3 写界面、动画、UI 交互
  • 最终产出一个 原生应用(Windows/Mac/Linux)
  • 体积只有 10–20MB
  • 启动速度不足 80ms

本文以示例项目:

👉 github.com/louis-xie-p…

为基础,通过大量真实源码解析,从入门安装到事件驱动架构,手把手带你构建一个 可复用、可扩展的桌面 GUI 框架

这篇文章特别适合:

  • 想用 Go 开发桌面应用
  • 想构建工具类客户端(下载器、日志工具、运维面板)
  • 想将 Vue3 应用迁移到桌面端
  • 想建立属于自己的桌面 UI 框架

准备好,我们开始吧。


🟦 第 1 部分:安装和创建Wails项目(官方正确方式)

官网地址:wails.io/zh-Hans/ ,具体的安装要求不高,不同的系统安装方法也很简单。

go install github.com/wailsapp/wails/v2/cmd/wails@latest
// 安装后检测一下系统环境是否满足要求
wails doctor

Wails 支持多种前端模板(Vue3 / React 等),找自己适合的创建 Vue3 + Vite 项目:

wails init -n MyApp -t vue

目录格式类似:

MyApp/
├── frontend/
├── build/
└── wails.json
└── app.go
└── main.go

进入开发模式(竟然还支持watch,太爽了):

wails dev

生产构建:

wails build

🟥 第 2 部分:wails.json 配置详解(结合你的项目)

“可配置,才自由”,任何框架约束越多越没有朋友。

你仓库中的配置如下(截取几个自定义的核心字段):

{
  "name": "wails-vue3-tmp",
  "author": "louis-xie-programmer",
  "assetdir": "",
  "frontend": {
    "dir": "frontend",
    "install": "yarn install",
    "build": "yarn build"
  },
  "devServerUrl": ""
}

🧩 assetdir: 前端资源文件路径,前端项目往往不由我。🧩 frontend:指定前端目录与构建命令;很多人喜欢npm, 但我喜欢yarn,还有人喜欢pnpm呢,习惯往往很难改变,有了它,我再也不用愁了,随便改,哪怕是是再命令行里定义环境变量呢,随你便,这才是真正的自由。🧩 devServerUrl这个更让自由飞了起来,默认为空,表示前端使用本地嵌入式调试服务器(Wails 自带)。如果你想让 Wails 使用你的 Vite 服务器就行。


🔄 第 3 部分:Go 后端代码详解(基于你的 backend/app.go)你的 backend/app.go 是整个后端的核心:

type App struct {
	ctx context.Context
}

func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
}

Wails 会自动调用:

  • startup
  • beforeClose
  • shutdown

让你在应用生命周期各阶段执行逻辑。


✔️ 你暴露的 RPC 示例:Greet

func (a *App) Greet(name string) string {
	return fmt.Sprintf("Hello %s", name)
}

前端将自动生成 TS 类型:

import { Greet } from "@/wailsjs/go/main/App";

const msg = await Greet("张三");
console.log(msg);

你无须写 HTTP、WebSocket,就是 RPC 调用。


✔️ 你自定义的事件推送方法:Emit

你自己封装了一个 Go → 前端的推送:

func (a *App) PushEvent(name string, payload interface{}) {
  if a.ctx == nil {
    fmt.Println("Warning: Context is nil, cannot emit event '" + name + "'")
    return
  }
  runtime.EventsEmit(a.ctx, name, payload) // 使用存储的上下文发送事件
}

后端可以像这样触发前端更新:

a.Emit("task_progress", i)

✔️ 后台任务示例

func (a *App) StartTestTimer() {
  ticker := time.NewTicker(2 * time.Second)
  go func() {
    for {
      select {
      case <-ticker.C:
        a.PushEvent("task_progress", rand.Intn(100))
        a.PushEvent("log", fmt.Sprintf("Log entry at %v", time.Now().Format("15:04:05")))
        a.PushEvent("notification", fmt.Sprintf("Notification received! (%d)", rand.Int31n(1000)))
      }
    }
  }()
}

这是桌面应用最常见的:

  • 文件处理
  • 批量任务
  • 后台执行
  • 数据同步

也是 Wails 的优势,因为:

Go 的并发 + 前端事件响应 = 完美适配桌面应用。


🟦 第 4 部分:前端事件系统

你在 frontend/src/utils/eventBus.ts 封装了前端事件系统。

/**
 * 定义事件回调函数类型
 * 接收任意类型的 payload 数据
 */
type EventCallback = (payload: any) => void;
class EventBus {
  // 存储所有事件监听器的映射表,键为事件名,值为回调函数数组
  private listeners: Record<string, EventCallback[]> = {};
  /**
   * 注册事件监听器
   * 同时尝试绑定到 Wails 运行时事件系统(如果可用)
   * @param event 事件名称
   * @param callback 回调函数
   */
  on(event: string, callback: EventCallback) {
    if (!this.listeners[event]) this.listeners[event] = [];
    this.listeners[event].push(callback);
    // 如果 Wails runtime 可用,则同时注册原生事件监听
    if ((window as any).runtime?.EventsOn) {
      (window as any).runtime.EventsOn(event, callback);
    }
  }
  /**
   * 移除事件监听器
   * @param event 事件名称
   * @param callback 要移除的回调函数
   */
  off(event: string, callback: EventCallback) {
    if (!this.listeners[event]) return;
    this.listeners[event] = this.listeners[event].filter(cb => cb !== callback);
  }
  /**
   * 触发事件,通知所有监听者
   * @param event 事件名称
   * @param payload 携带的数据
   */
  emit(event: string, payload: any) {
    if (this.listeners[event]) {
      this.listeners[event].forEach(cb => cb(payload));
    }
  }
}
// 导出单例事件总线实例,用于整个应用的事件通信
export const eventBus = new EventBus();

你实现了:

  • 前端订阅 Go 事件
  • 前端 emit 到 Go
  • 同事件多监听器
  • 自动分发数据

比 Wails 原生事件 API 更好用。


🟩 第 5 部分:Pinia 状态管理

你在 store/event.ts 中写了一个全局事件状态:

/**
 * 定义事件存储(Event Store)
 * 使用 Pinia 创建一个名为 'event' 的状态存储
 * 包含任务进度、日志和通知等实时数据
 */
export const useEventStore = defineStore('event', {
  state: () => ({
    taskProgress: 0, // 当前任务完成进度百分比
    logs: [] as string[], // 存储日志消息的数组
    notifications: [] as string[] // 存储通知消息的数组
  }),
  actions: {
    /**
     * 初始化事件监听器
     * 监听通过 eventBus 发送的各类事件,并更新状态
     */
    initEventListeners() {
      // 监听 'task_progress' 事件,更新任务进度
      eventBus.on('task_progress', (progress: number) => { this.taskProgress = progress; });
      // 监听 'log' 事件,将新日志添加到日志列表
      eventBus.on('log', (message: string) => { this.logs.push(message); });
      // 监听 'notification' 事件,将新通知添加到通知列表
      eventBus.on('notification', (msg: string) => { this.notifications.push(msg); });
    },
    /**
     * 清空所有日志
     */
    clearLogs() { this.logs = []; },
    /**
     * 清空所有通知
     */
    clearNotifications() { this.notifications = []; }
  }
});

🟥 第 6 部分:在你的项目中如何构建 UI(Vue3)

由于朋友们大部分都是Go后端开发,vue3可能不熟悉,所以这里还是讲一下。

  • components 目录是自定义组件:
  • GreetBox.vue   TaskProgress.vue;
  • views 目录下面是页面文件;
  • 而 router.ts 是路由文件;

App.vue 文件修改:

<script lang="ts" setup>
</script>
<template>
  //修改走路由指定
  <router-view />
</template>
<style>
</style>

Wails + Vue3 是 Go 桌面应用最强组合

Wails 让 Go 开发者第一次拥有:

  • 现代 UI(Vue3)
  • 高性能后端(Go)
  • 轻量产物(<20MB)
  • 跨平台支持
  • 事件驱动架构
  • 响应式 UI

而你这个 wails-vue3-tmp 项目是:

一个真正“可复用、可扩展、可维护”的桌面客户端开发基座。

放到企业内部完全可以成为主力模板。喜欢它的自由和纯粹。

Github 源码:

https://github.com/louis-xie-programmer/wails-vue3-tmp

Gitee 源码:

https://gitee.com/louis_xie/wails-vue3-tmp