コントリビュート

このドキュメントを編集

ドキュメントを翻訳するか、お使いのコンピューターでプロジェクト全体を開きます。

作業内容を送信するまで、何も公開されません。

Wails の仕組み

Wails のアーキテクチャと、ネイティブパフォーマンスを実現する仕組みを理解する

Wails は、バックエンドに Go、フロントエンドに Web 技術を使用してデスクトップアプリケーションを構築するためのフレームワークです。ただし Electron とは異なり、ブラウザーを同梱せず、オペレーティングシステムのネイティブ WebViewを使用します。

Wails アプリ, フロントエンド, Go バックエンド, オペレーティングシステム, 初期化, 静的 Web アプリを配信, OS ネイティブの WebView でサイトをレンダリング, 通常の通信, API 形式で呼び出す, サービスがリクエストを処理, レスポンスを生成, レスポンスを処理

Electron との主な違い:

項目 Wails Electron
ブラウザー OS が提供する WebView 同梱の Chromium(約 100MB)
バックエンド Go(コンパイル済み) Node.js(インタープリター実行)
通信 インメモリブリッジ IPC(プロセス間通信)
バンドルサイズ 約 15MB 約 150MB
メモリ 約 10MB 約 100MB 以上
起動時間 <0.5s 2-3s

コアコンポーネント

1. ネイティブ WebView

Wails は、オペレーティングシステムに組み込まれた Web レンダリングエンジンを使用します。

WebView2(Microsoft Edge WebView2)

  • Chromium ベース(Edge ブラウザーと同じ)
  • Windows 10/11 にプリインストール済み
  • Windows Update による自動更新
  • 最新の Web 標準を完全にサポート

これが重要な理由:

  • ブラウザーを同梱しない → アプリのサイズを縮小
  • OS ネイティブ → 統合性とパフォーマンスが向上
  • 自動更新 → OS の更新によってセキュリティパッチを適用
  • 使い慣れたレンダリング → システムブラウザーと同じ

2. Wails ブリッジ

ブリッジは Wails の中核であり、Go と JavaScript の間の直接通信を可能にします。

フロントエンド(JavaScript), Wails ブリッジ, JSON エンコーダー, メソッドルーター, JSON デコーダー, バックエンド(Go), 登録済みサービス

仕組み:

  1. フロントエンドが Go メソッドを呼び出す(自動生成されたバインディング経由)
  2. ブリッジが呼び出しを JSON にエンコードする(メソッド名と引数)
  3. ルーターが登録済みサービス内から Go メソッドを見つける
  4. Go メソッドが実行され、値を返す
  5. ブリッジが結果をデコードし、フロントエンドに返す
  6. JavaScript で結果を受け取って Promise が解決される

パフォーマンス特性:

  • インメモリ:ネットワークのオーバーヘッドも HTTP もなし
  • 可能な場合はゼロコピー(大容量データ向け)
  • デフォルトで非同期:どちら側もブロックしない
  • 型安全:TypeScript の型定義を自動生成

3. サービスシステム

フロントエンドに Go の機能を公開するには、サービスの使用を推奨します。

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 は起動時に構造体をスキャンします
  • エクスポートされたメソッドをフロントエンドから呼び出せるようになります
  • TypeScript バインディング用に型情報が抽出されます
  • エラー処理は自動です(Go のエラー → JS の例外)

生成された TypeScript バインディング:

typescript
// Auto-generated in frontend/bindings/GreetService.ts
export function Greet(name: string): Promise<string>
export function GetTime(): Promise<Date>

サービスを使用する理由:

  • 型安全:TypeScriptを完全にサポート
  • 自動検出:メソッドを手動で登録する必要はありません
  • 体系的な整理:関連する機能をグループ化
  • テスト可能:サービスは単なるGo構造体です

サービスの詳細 →

4. イベントシステム

イベントにより、コンポーネント間でパブリッシュ/サブスクライブ通信を行えます。

Wails イベントシステム, ウィンドウ 1, ウィンドウ 2, Go バックエンド, イベントドライバー, 'data-updated' イベントを購読, 'data-updated' イベントを購読, アプリが Emit('data-updated', data) を実行, 購読側が On('data-updated', handler) で処理, 購読側が On('data-updated', handler) で処理

ユースケース:

  • ウィンドウ間通信:あるウィンドウから別のウィンドウへ通知
  • バックグラウンドタスク:GoサービスからUIへ進捗を通知
  • 状態の同期:複数のウィンドウを同期した状態に維持
  • 疎結合:コンポーネント間の直接参照が不要

例:

go
// Go: Emit an event
app.Event.Emit("user-logged-in", user)
javascript
// JavaScript: Listen for event
import { Events } from '@wailsio/runtime'

Events.On('user-logged-in', (user) => {
    console.log('User logged in:', user)
})

イベントの詳細 →

アプリケーションのライフサイクル

ライフサイクルを理解すると、リソースを初期化するタイミングとクリーンアップするタイミングが分かります。

アプリケーションの起動, 初期化, アプリケーションを作成, サービスを登録, ウィンドウ/メニューを設定, イベントループ, イベントを処理, メッセージを処理, UI を更新, シャットダウン, リソースを解放, 状態を保存, アプリケーションの終了

ライフサイクルフック:

go
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 コード (main.go, サービス), フロントエンドコード (HTML/CSS/JS), ビルドプロセス, Go コードを解析, バインディングを生成, フロントエンドをビルド, Go をコンパイル, アセットを埋め込む, 出力, ネイティブバイナリ (myapp.exe/.app)

ビルド手順:

  1. Goコードを解析
  • サービスを走査してエクスポート済みメソッドを検出
  • パラメーターと戻り値の型を抽出
  • メソッドシグネチャを生成
  1. TypeScriptバインディングを生成
  • サービスごとに.tsファイルを作成
  • 完全な型定義を含める
  • JSDocコメントを追加
  1. フロントエンドをビルド
  • バンドラー(Vite、webpackなど)を実行
  • ミニファイして最適化
  • frontend/dist/に出力
  1. Goをコンパイル
  • 最適化を有効にしてコンパイル(-ldflags="-s -w")
  • ビルドメタデータを含める
  • プラットフォーム固有のコンパイルを実行
  1. アセットを埋め込む
  • フロントエンドファイルをGoバイナリに埋め込む
  • アセットを圧縮
  • 単一の実行可能ファイルを作成

結果:すべてが埋め込まれた単一のネイティブ実行可能ファイル。

ビルドの詳細 →

開発環境と本番環境

Wailsの動作は、開発環境と本番環境で異なります。

特性:

  • ホットリロード:フロントエンドの変更を即座に再読み込み
  • ソースマップ:元のソースコードを使用してデバッグ
  • DevTools:ブラウザーのDevToolsを使用可能
  • ログ出力:詳細なログ出力を有効化
  • 外部フロントエンド:開発サーバー(Vite)から配信

仕組み:

Wails アプリ, Vite 開発サーバー (localhost:5173), WebView

利点:

  • 変更結果を即座に確認
  • すべてのデバッグ機能を利用可能
  • 反復作業を高速化

メモリモデル

メモリ使用量を理解すると、効率的なアプリケーションを構築できます。

メモリ領域:

  1. Goヒープ
  • サービスとアプリケーションの状態
  • Goのガベージコレクターによって管理
  • 単純なアプリでは通常5-10MB
  1. WebViewのメモリ
  • DOM、JavaScriptヒープ、CSS
  • WebViewのエンジンによって管理
  • 単純なアプリでは通常10-20MB
  1. ブリッジのメモリ
  • 通信用のメッセージバッファ
  • 最小限のオーバーヘッド(<1MB)
  • 可能な場合は大容量データをゼロコピーで処理

最適化のヒント:

  • 大容量データの転送を避ける:IDを渡し、詳細は必要に応じて取得します
  • 更新にはイベントを使用する:フロントエンドからポーリングしないでください
  • 大きなファイルをストリーミングする:ファイル全体をメモリに読み込まないでください
  • リスナーをクリーンアップする:不要になったイベントリスナーは削除してください

パフォーマンスについて詳しく見る →

セキュリティモデル

Wailsは、デフォルトで安全なアーキテクチャを提供します:

フロントエンド(信頼されていない), Wails ブリッジ(検証), バックエンド(信頼されている)

セキュリティ機能:

  1. メソッドの許可リスト
  • 呼び出せるのはエクスポートされたメソッドのみ
  • 非公開メソッドにはアクセス不可
  • サービスの明示的な登録が必要
  1. 型の検証
  • 引数をGoの型と照合
  • 無効な型を拒否
  • インジェクション攻撃を防止
  1. eval()を使用しない
  • フロントエンドから任意のGoコードを実行することは不可
  • 呼び出せるのは事前定義されたメソッドのみ
  • 動的なコード実行なし
  1. コンテキストの分離
  • 各ウィンドウが独自のコンテキストを保持
  • サービスで呼び出し元のコンテキストを確認可能
  • ウィンドウごとの権限設定が可能

ベストプラクティス:

  • Goでユーザー入力を検証する(フロントエンドを信頼しないでください)
  • 認証と認可にはコンテキストを使用する
  • ファイル操作の前にファイルパスをサニタイズする
  • 高コストな処理をレート制限する

セキュリティについて詳しく見る →

次のステップ

アプリケーションのライフサイクル - 起動、終了、ライフサイクルフックについて理解します 詳しく見る →

Goとフロントエンド間のブリッジ - ブリッジの仕組みを詳しく掘り下げます 詳しく見る →

ビルドシステム - Wailsがアプリケーションをビルドする仕組みを理解します 詳しく見る →

構築を始める - ここまでに学んだことをチュートリアルで実践します チュートリアル →


アーキテクチャについて質問がありますか? Discordで質問するか、APIリファレンスを確認してください。

ページを編集

最終更新: