293 lines
6.0 KiB
Markdown
293 lines
6.0 KiB
Markdown
# 基于 Wails 的桌面程序搭建
|
||
|
||
## 技术栈
|
||
|
||
- Go v1.25.4
|
||
- Wails v2
|
||
- Arco Design Vue
|
||
- Vue 3
|
||
|
||
## 环境准备
|
||
|
||
### 1. 安装 Wails CLI
|
||
|
||
```bash
|
||
go install github.com/wailsapp/wails/v2/cmd/wails@latest
|
||
```
|
||
|
||
### 2. 验证安装
|
||
|
||
```bash
|
||
wails version
|
||
```
|
||
|
||
## 项目初始化
|
||
|
||
### 1. 创建项目
|
||
|
||
```bash
|
||
wails init -n go-desk -t vanilla
|
||
```
|
||
|
||
### 2. 项目结构
|
||
|
||
```
|
||
go-desk/
|
||
├── app.go # 应用逻辑,暴露给前端的方法
|
||
├── main.go # 程序入口,初始化 Wails 应用
|
||
├── wails.json # Wails 配置文件
|
||
├── go.mod # Go 模块依赖
|
||
├── go.sum # Go 依赖校验
|
||
├── frontend/ # 前端代码目录
|
||
│ ├── package.json # 前端依赖配置
|
||
│ ├── package-lock.json # 依赖锁定文件
|
||
│ ├── vite.config.js # Vite 构建配置
|
||
│ ├── index.html # HTML 入口文件
|
||
│ ├── src/
|
||
│ │ ├── main.js # Vue 应用入口
|
||
│ │ ├── App.vue # 根组件
|
||
│ │ └── style.css # 全局样式
|
||
│ └── dist/ # 构建产物(构建后生成)
|
||
│ ├── index.html
|
||
│ ├── assets/
|
||
│ └── ...
|
||
├── build/ # 构建资源目录
|
||
│ ├── appicon.png # 应用图标
|
||
│ └── windows/ # Windows 构建资源(可选)
|
||
│ └── icon.ico
|
||
└── build/bin/ # 编译后的可执行文件(构建后生成)
|
||
└── go-desk.exe # Windows 可执行文件
|
||
```
|
||
|
||
**目录说明:**
|
||
- `app.go`: 定义应用结构体和方法,供前端调用
|
||
- `main.go`: 程序入口,配置窗口、资源等
|
||
- `frontend/`: 前端 Vue 项目,使用 Vite 构建
|
||
- `frontend/dist/`: 前端构建产物,会被嵌入到 Go 二进制文件
|
||
- `build/`: 应用图标等构建资源
|
||
|
||
## 配置调整
|
||
|
||
### 1. 配置 Wails 使用 web 目录
|
||
|
||
如果使用 `web` 作为前端目录(而非默认的 `frontend`),需要在 `wails.json` 中配置:
|
||
|
||
```json
|
||
{
|
||
"frontend": {
|
||
"dir": "web"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 安装 Arco Design Vue
|
||
|
||
```bash
|
||
cd web
|
||
npm install --save @arco-design/web-vue
|
||
```
|
||
|
||
### 3. 修改 `frontend/src/main.js`
|
||
|
||
```javascript
|
||
import { createApp } from 'vue'
|
||
import ArcoVue from '@arco-design/web-vue'
|
||
import '@arco-design/web-vue/dist/arco.css'
|
||
import './style.css'
|
||
import App from './App.vue'
|
||
|
||
const app = createApp(App)
|
||
app.use(ArcoVue)
|
||
app.mount('#app')
|
||
```
|
||
|
||
### 4. 修改 `frontend/src/App.vue`
|
||
|
||
```vue
|
||
<template>
|
||
<a-layout class="layout">
|
||
<a-layout-header>
|
||
<div class="header-content">
|
||
<h2>Go Desk Demo</h2>
|
||
</div>
|
||
</a-layout-header>
|
||
<a-layout-content class="content">
|
||
<a-card>
|
||
<template #title>欢迎</template>
|
||
<p>这是一个基于 Wails + Arco-Vue 的最小 Demo</p>
|
||
<a-button type="primary" @click="handleClick">点击测试</a-button>
|
||
<p v-if="message">{{ message }}</p>
|
||
</a-card>
|
||
</a-layout-content>
|
||
</a-layout>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'App',
|
||
data() {
|
||
return {
|
||
message: ''
|
||
}
|
||
},
|
||
methods: {
|
||
async handleClick() {
|
||
// 调用 Go 后端方法
|
||
if (window.go && window.go.main && window.go.main.Greet) {
|
||
try {
|
||
const result = await window.go.main.Greet('World')
|
||
this.message = result
|
||
} catch (error) {
|
||
this.message = '调用失败: ' + error.message
|
||
}
|
||
} else {
|
||
this.message = 'Go 后端未就绪'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.layout {
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.header-content {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 100%;
|
||
padding: 0 20px;
|
||
color: var(--color-text-1);
|
||
}
|
||
|
||
.content {
|
||
padding: 20px;
|
||
flex: 1;
|
||
overflow: auto;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
### 5. 修改 `app.go` - Go 后端
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
)
|
||
|
||
// App struct
|
||
type App struct {
|
||
ctx context.Context
|
||
}
|
||
|
||
// NewApp creates a new App application struct
|
||
func NewApp() *App {
|
||
return &App{}
|
||
}
|
||
|
||
// startup is called when the app starts. The context is saved
|
||
// so we can call the runtime methods
|
||
func (a *App) startup(ctx context.Context) {
|
||
a.ctx = ctx
|
||
}
|
||
|
||
// Greet returns a greeting for the given name
|
||
func (a *App) Greet(name string) string {
|
||
return fmt.Sprintf("Hello %s, It's show time!", name)
|
||
}
|
||
```
|
||
|
||
### 6. 修改 `main.go`
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"context"
|
||
"embed"
|
||
|
||
"github.com/wailsapp/wails/v2"
|
||
"github.com/wailsapp/wails/v2/pkg/options"
|
||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||
)
|
||
|
||
//go:embed all:frontend/dist
|
||
var assets embed.FS
|
||
|
||
func main() {
|
||
// Create an instance of the app structure
|
||
app := NewApp()
|
||
|
||
// Create application with options
|
||
err := wails.Run(&options.App{
|
||
Title: "Go Desk",
|
||
Width: 1024,
|
||
Height: 768,
|
||
AssetServer: &assetserver.Options{
|
||
Assets: assets,
|
||
},
|
||
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
|
||
OnStartup: app.startup,
|
||
})
|
||
|
||
if err != nil {
|
||
println("Error:", err.Error())
|
||
}
|
||
}
|
||
```
|
||
|
||
## 开发运行
|
||
|
||
### 1. 开发模式
|
||
|
||
```bash
|
||
# 终端1:启动前端开发服务器
|
||
cd web
|
||
npm run dev
|
||
|
||
# 终端2:启动 Wails 开发模式
|
||
wails dev
|
||
```
|
||
|
||
### 2. 构建前端
|
||
|
||
```bash
|
||
cd web
|
||
npm run build
|
||
```
|
||
|
||
### 3. 构建应用
|
||
|
||
```bash
|
||
# 构建当前平台
|
||
wails build
|
||
|
||
# 构建 Windows
|
||
wails build -platform windows/amd64
|
||
|
||
# 构建 macOS
|
||
wails build -platform darwin/amd64
|
||
|
||
# 构建 Linux
|
||
wails build -platform linux/amd64
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. **前端构建**:每次修改前端代码后需要重新构建 `npm run build`,Wails 会使用 `frontend/dist` 目录
|
||
2. **Go 方法暴露**:在 `app.go` 中定义的方法会自动暴露给前端,通过 `window.go.main.MethodName` 调用
|
||
3. **热重载**:开发模式下,Go 代码修改需要重启 `wails dev`,前端代码修改需要重新构建
|
||
4. **资源嵌入**:使用 `//go:embed` 将前端构建产物嵌入到 Go 二进制文件中
|
||
|
||
## 参考
|
||
|
||
- [Wails 官方文档](https://wails.io/docs/)
|
||
- [Arco Design Vue](https://arco.design/vue/docs/start)
|
||
|