Wails 的運作方式
瞭解 Wails 架構及其如何實現原生效能
Wails 是一個桌面應用程式開發框架,使用Go 建構後端,並使用網頁技術建構前端。但與 Electron 不同,Wails 不會內附瀏覽器,而是使用作業系統的原生 WebView。
與 Electron 的主要差異:
| 面向 | Wails | Electron |
|---|---|---|
| 瀏覽器 | 作業系統提供的 WebView | 內附 Chromium(約 100MB) |
| 後端 | Go(編譯執行) | Node.js(直譯執行) |
| 通訊 | 記憶體內橋接器 | IPC(處理程序間通訊) |
| 套件大小 | 約 15MB | 約 150MB |
| 記憶體 | 約 10MB | 約 100MB 以上 |
| 啟動時間 | <0.5 秒 | 2-3 秒 |
核心元件
1. 原生 WebView
Wails 使用作業系統內建的網頁轉譯引擎:
WebView2(Microsoft Edge WebView2)
- 以 Chromium 為基礎(與 Edge 瀏覽器相同)
- 預先安裝於 Windows 10/11
- 透過 Windows Update 自動更新
- 完整支援現代網頁標準
WebKit(Safari 的轉譯引擎)
- 內建於 macOS
- 與 Safari 瀏覽器使用相同引擎
- 效能與電池續航力極佳
- 完整支援現代網頁標準
WebKitGTK(WebKit 的 GTK 移植版本)
- 透過套件管理員安裝
- 與 GNOME Web(Epiphany)使用相同引擎
- 良好支援網頁標準
- 輕量且效能優異
這一點為何重要:
- 不內附瀏覽器 → 應用程式更小
- 作業系統原生 → 整合度與效能更佳
- 自動更新 → 透過作業系統更新取得安全性修補程式
- 熟悉的轉譯結果 → 與系統瀏覽器相同
2. Wails 橋接器
橋接器是 Wails 的核心,可讓 Go 與 JavaScript 之間進行直接通訊。
運作方式:
- 前端呼叫 Go 方法(透過自動產生的繫結)
- 橋接器將呼叫編碼為 JSON(方法名稱 + 引數)
- 路由器在已註冊的服務中尋找 Go 方法
- Go 方法執行並傳回值
- 橋接器將結果解碼並傳回前端
- JavaScript 中的Promise 以該結果完成
效能特性:
- 記憶體內通訊:沒有網路額外負擔,也不使用 HTTP
- 盡可能採用零複製(適用於大型資料)
- 預設為非同步:兩端皆不會阻塞
- 型別安全:自動產生 TypeScript 定義
3. 服務系統
建議透過服務將 Go 功能公開給前端。
// Define a service (just a regular Go struct)
type GreetService struct {
prefix string
}
// Methods with exported names are automatically available
func (g *GreetService) Greet(name string) string {
return g.prefix + name + "!"
}
func (g *GreetService) GetTime() time.Time {
return time.Now()
}
// Register the service
app := application.New(application.Options{
Services: []application.Service{
application.NewService(&GreetService{prefix: "Hello, "}),
},
})服務探索:
- Wails 會在啟動時掃描您的 struct
- 匯出的方法可供前端呼叫
- 系統會擷取型別資訊,用於 TypeScript 繫結
- 錯誤處理會自動進行(Go 錯誤 → JS 例外)
產生的 TypeScript 繫結:
// Auto-generated in frontend/bindings/GreetService.ts
export function Greet(name: string): Promise<string>
export function GetTime(): Promise<Date>為何使用服務?
- 型別安全:完整支援 TypeScript
- 自動探索:無須手動註冊方法
- 條理分明:將相關功能分組
- 可測試:服務只是 Go 結構體
4. 事件系統
事件讓元件之間能透過發布/訂閱模式進行通訊。
使用情境:
- 視窗通訊:一個視窗通知其他視窗
- 背景工作:Go 服務向 UI 通知進度
- 狀態同步:讓多個視窗保持同步
- 鬆散耦合:元件不需要直接參照彼此
範例:
// Go: Emit an event
app.Event.Emit("user-logged-in", user)// JavaScript: Listen for event
import { Events } from '@wailsio/runtime'
Events.On('user-logged-in', (user) => {
console.log('User logged in:', user)
})應用程式生命週期
瞭解生命週期有助於掌握初始化資源及執行清理的時機。
生命週期掛鉤:
app := application.New(application.Options{
Name: "My App",
// Cleanly intercept quit requests (e.g. unsaved changes).
ShouldQuit: func() bool { return true },
// Called when the app is confirmed to be quitting — save state, close connections, etc.
OnShutdown: func() {},
})application.Options上沒有OnStartup欄位。啟動工作應放在服務的ServiceStartup(ctx, options)中、透過app.Event.OnApplicationEvent(events.Common.ApplicationStarted, ...)註冊的回呼中,或直接放在app.Run()之前。
建置流程
瞭解 Wails 如何建置應用程式:
建置步驟:
- 分析 Go 程式碼
- 掃描服務中的匯出方法
- 擷取參數與傳回型別
- 產生方法簽章
- 產生 TypeScript 繫結
- 為每個服務建立
.ts檔案 - 包含完整的型別定義
- 新增 JSDoc 註解
- 建置前端
- 執行打包工具(Vite、webpack 等)
- 縮小並最佳化
- 輸出至
frontend/dist/
- 編譯 Go
- 啟用最佳化進行編譯(
-ldflags="-s -w") - 包含建置中繼資料
- 針對特定平台進行編譯
- 嵌入資產
- 將前端檔案嵌入 Go 二進位檔
- 壓縮資產
- 建立單一可執行檔
結果:所有內容均已嵌入的單一原生可執行檔。
開發環境與正式環境
Wails 在開發環境與正式環境中的行為有所不同:
特性:
- 熱重載:前端變更會立即重新載入
- 原始碼對應表:使用原始程式碼進行偵錯
- DevTools:可使用瀏覽器 DevTools
- 記錄:啟用詳細記錄
- 外部前端:由開發伺服器(Vite)提供
運作方式:
優點:
- 立即取得變更回饋
- 完整的偵錯功能
- 加快反覆開發速度
特性:
- 嵌入式資產:前端已建置到二進位檔中
- 已最佳化:經過縮小與壓縮
- 無 DevTools:預設停用
- 最少量記錄:僅記錄錯誤
- 單一檔案:所有內容都在一個可執行檔中
運作方式:
優點:
- 單一檔案發佈
- 檔案更小(經過最小化)
- 效能更佳
- 無外部相依項目
記憶體模型
瞭解記憶體使用情況,有助於建置高效率的應用程式。
記憶體區域:
- Go 堆積
- 您的服務與應用程式狀態
- 由 Go 垃圾回收器管理
- 簡易應用程式通常為 5-10MB
- WebView 記憶體
- DOM、JavaScript 堆積、CSS
- 由 WebView 引擎管理
- 簡易應用程式通常為 10-20MB
- 橋接層記憶體
- 用於通訊的訊息緩衝區
- 額外負擔極低(<1MB)
- 大型資料會盡可能採用零複製
最佳化提示:
- 避免傳輸大量資料:傳遞 ID,並視需要擷取詳細資料
- 使用事件進行更新:不要從前端輪詢
- 以串流方式處理大型檔案:不要將整個檔案載入記憶體
- 清除監聽器:使用完畢後移除事件監聽器
安全性模型
Wails 提供預設安全的架構:
安全性功能:
- 方法白名單
- 只能呼叫匯出的方法
- 無法存取私有方法
- 必須明確註冊服務
- 型別驗證
- 依據 Go 型別檢查引數
- 拒絕無效的型別
- 防止注入攻擊
- 不使用 eval()
- 前端無法執行任意 Go 程式碼
- 只能呼叫預先定義的方法
- 不會動態執行程式碼
- 情境隔離
- 每個視窗都有自己的情境
- 服務可以檢查呼叫端的情境
- 可為每個視窗設定不同權限
最佳實務:
- 在 Go 中驗證使用者輸入(不要信任前端)
- 使用情境進行驗證與授權
- 執行檔案操作前,先清理檔案路徑
- 對高成本操作實施速率限制
後續步驟
應用程式生命週期 - 瞭解啟動、關閉及生命週期掛鉤 深入瞭解 →
Go 與前端的橋接層 - 深入探討橋接層的運作方式 深入瞭解 →
建置系統 - 瞭解 Wails 如何建置您的應用程式 深入瞭解 →
開始建置 - 透過教學實作所學內容 教學 →