Wails 運作原理
Wails 是一個用於構建桌面應用程式的框架,採用 Go 作為後端 和 Web 技術作為前端。但與 Electron 不同,Wails 並未捆綁瀏覽器,而是使用 作業系統的原生 WebView。
與 Electron 的主要差異:
| 面向 | Wails | Electron |
|---|---|---|
| 瀏覽器 | 作業系統提供的 WebView | 捆綁 Chromium(約 100MB) |
| 後端 | Go(編譯後) | Node.js(解釋執行) |
| 通訊 | 記憶體橋接 | IPC(進程間通訊) |
| 套件大小 | 約 15MB | 約 150MB |
| 記憶體佔用 | 約 10MB | 約 100MB+ |
| 啟動速度 | <0.5 秒 | 2-3 秒 |
1. 原生 WebView
Section titled “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 橋接器
Section titled “2. Wails 橋接器”橋接器是 Wails 的核心——它實現了 Go 與 JavaScript 之間的直接通訊。
運作方式:
- 前端呼叫 Go 方法(透過自動產生的繫結)
- 橋接器將呼叫編碼為 JSON(方法名稱 + 參數)
- 路由器在已註冊的服務中找到 Go 方法
- Go 方法執行並返回值
- 橋接器解碼結果並傳回前端
- JavaScript 中的 Promise 解析並獲得結果
效能特性:
- 記憶體內:無網路開銷,無 HTTP
- 零複製(在可能的情况下,針對大量資料)
- 預設非同步:兩側均非阻塞
- 型別安全:自動產生 TypeScript 定義
3. 服務系統
Section titled “3. 服務系統”服務是向後端暴露 Go 功能的推薦方式。
// Define a service (just a regular Go struct)type GreetService struct { prefix string}
// Methods with exported names are automatically availablefunc (g *GreetService) Greet(name string) string { return g.prefix + name + "!"}
func (g *GreetService) GetTime() time.Time { return time.Now()}
// Register the serviceapp := application.New(application.Options{ Services: []application.Service{ application.NewService(&GreetService{prefix: "Hello, "}), },})服務發現:
- Wails 在啟動時掃描您的結構體
- 公開方法可從前端呼叫
- 型別資訊被提取用於 TypeScript 繫結
- 錯誤處理是自動的(Go 錯誤 → JS 異常)
產生的 TypeScript 繫結:
// Auto-generated in frontend/bindings/GreetService.tsexport function Greet(name: string): Promise<string>export function GetTime(): Promise<Date>為什麼使用服務?
- 型別安全:完整的 TypeScript 支援
- 自動發現:無需手動註冊方法
- 組織良好:分組相關功能
- 可測試:服務只是 Go 結構體
4. 事件系統
Section titled “4. 事件系統”事件實現元件之間的發布/訂閱通訊。
使用情境:
- 視窗通訊:一個視窗通知其他視窗
- 背景任務:Go 服務通知 UI 進度
- 狀態同步:保持多個視窗同步
- 鬆耦合:元件不需要直接參考
範例:
// Go: Emit an eventapp.Event.Emit("user-logged-in", user)// JavaScript: Listen for eventimport { Events } from '@wailsio/runtime'
Events.On('user-logged-in', (user) => { console.log('User logged in:', user)})應用程式生命週期
Section titled “應用程式生命週期”了解生命週期可幫助您知道何時初始化資源和清理。
Lifecycle hooks:
app := application.New(application.Options{ Name: "My App",
// Called before windows are created OnStartup: func(ctx context.Context) { // Initialise database, load config, etc. },
// Called when app is about to quit OnShutdown: func() { // Save state, close connections, etc. },})Build Process
Section titled “Build Process”Understanding how Wails builds your application:
Build steps:
-
Analyse Go code
- Scan services for exported methods
- Extract parameter and return types
- Generate method signatures
-
Generate TypeScript bindings
- Create
.tsfiles for each service - Include full type definitions
- Add JSDoc comments
- Create
-
Build frontend
- Run your bundler (Vite, webpack, etc.)
- Minify and optimise
- Output to
frontend/dist/
-
Compile Go
- Compile with optimisations (
-ldflags="-s -w") - Include build metadata
- Platform-specific compilation
- Compile with optimisations (
-
Embed assets
- Embed frontend files into Go binary
- Compress assets
- Create single executable
Result: A single native executable with everything embedded.
Development vs Production
Section titled “Development vs Production”Wails behaves differently in development and production:
Characteristics:
- Hot reload: Frontend changes reload instantly
- Source maps: Debug with original source
- DevTools: Browser DevTools available
- Logging: Verbose logging enabled
- External frontend: Served from dev server (Vite)
How it works:
Benefits:
- Instant feedback on changes
- Full debugging capabilities
- Faster iteration
Characteristics:
- Embedded assets: Frontend built into binary
- Optimised: Minified, compressed
- No DevTools: Disabled by default
- Minimal logging: Errors only
- Single file: Everything in one executable
How it works:
Benefits:
- Single file distribution
- Smaller size (minified)
- Better performance
- No external dependencies
Memory Model
Section titled “Memory Model”Understanding memory usage helps you build efficient applications.
Memory regions:
-
Go Heap
- Your services and application state
- Managed by Go garbage collector
- Typically 5-10MB for simple apps
-
WebView Memory
- DOM, JavaScript heap, CSS
- Managed by WebView’s engine
- Typically 10-20MB for simple apps
-
Bridge Memory
- Message buffers for communication
- Minimal overhead (<1MB)
- Zero-copy for large data where possible
Optimisation tips:
- Avoid large data transfers: Pass IDs, fetch details on demand
- Use events for updates: Don’t poll from frontend
- Stream large files: Don’t load entirely into memory
- Clean up listeners: Remove event listeners when done
Learn more about performance →
Security Model
Section titled “Security Model”Wails provides a secure-by-default architecture:
Security features:
-
Method whitelisting
- Only exported methods are callable
- Private methods are inaccessible
- Explicit service registration required
-
Type validation
- Arguments checked against Go types
- Invalid types rejected
- Prevents injection attacks
-
No eval()
- Frontend can’t execute arbitrary Go code
- Only predefined methods callable
- No dynamic code execution
-
Context isolation
- Each window has its own context
- Services can check caller context
- Permissions per window possible
Best practices:
- Validate user input in Go (don’t trust frontend)
- Use context for authentication/authorisation
- Sanitise file paths before file operations
- Rate limit expensive operations
Next Steps
Section titled “Next Steps”Application Lifecycle - Understand startup, shutdown, and lifecycle hooks
Learn More →
Go-Frontend Bridge - Deep dive into how the bridge works
Learn More →
Build System - Understand how Wails builds your application
Learn More →
Start Building - Apply what you’ve learned in a tutorial Tutorials →