mcpField
W
wails

wails

github.com/spf13開発687149 回インストール4 日前に更新
リポジトリ

wails について

Go バックエンドとプラットフォームの WebView フロントエンドでデスクトップアプリを構築するための Wails ガイドです。安定版 v2 とアルファ版 v3 を扱い、互換性のない API の混在を避けるため、まずバージョンを確認します。

主な機能

  1. 01Go と Web フロントエンドのデスクトップアプリを解説
  2. 02Wails v2 と v3 を個別に説明
  3. 03バージョン判定と対応 API を案内
  4. 04バインディング、イベント、ビルドを解説
  5. 05v3 の MCP 組み込み機能を説明

活用シーン

  1. 01新規プロジェクトの Wails バージョン選択
  2. 02v2 と v3 の API 混在の診断
  3. 03Go とフロントエンドのバインディング設計
  4. 04Wails MCP によるアプリテスト

MCP 対応

Wails v3 は WAILS_MCP=1 でビルドすると、MCP サーバーをアプリに組み込めます。MCP クライアントからウィンドウ操作、DOM 検査、バインドされたメソッドの呼び出しができます。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/spf13/go-skills --skill wails

インストール後、Claude Code で/wailsを入力して読み込まれたか確認します。

同梱ファイル.claude-plugin/plugin.json

詳細

Wails:Go でデスクトップアプリを構築

Wails は、Go バックエンドと、プラットフォームの WebView(macOS/Linux では WebKit、Windows では WebView2)でレンダリングされる Web フロントエンドを使って、ネイティブのデスクトップアプリケーションを構築します。Chromium は同梱されないため、バイナリのサイズは数百メガバイトではなく、数メガバイトです。

互換性のない API を持つ 2 つのメジャーバージョンが共存しています。 v2 は安定版です。v3(2026 年半ば時点)はアルファ版の後期段階です。API はかなり安定しており、本番アプリもリリースされていますが、リリースは夜間ビルドの v3.0.0-alpha2.x タグで、詳細はまだ変更される可能性があります。特に LLM で最もよく見られる失敗は、v2 と v3 のコードを混在させることです。すべての回答は、v2 か v3 のどちらか一方だけにしてください。

ステップ 0 — バージョンを特定する(必須)

コードを書く前に、プロジェクトからバージョンを特定してください。ユーザーの表現から推測してはいけません。

シグナルv2v3
go.mod のインポートgithub.com/wailsapp/wails/v2github.com/wailsapp/wails/v3
CLIwails(wails dev、wails build)wails3(wails3 dev、wails3 build)
ビルドのオーケストレーション不透明で、wails.json によって制御Taskfile.yml(go-task)を使用し、透明性が高い
エントリーポイントwails.Run(&options.App{...})application.New(application.Options{...})
Go → JS の公開Bind: []interface{}{app}Services: []application.Service{...}
ランタイム呼び出しコンテキストを保存して runtime.EventsEmit(ctx, ...)app / window のメソッドを使用 — コンテキストの受け渡しは不要
フロントエンドのインポートwailsjs/go/main/Appfrontend/bindings/<import-path>/<service>

まだコードのない新規プロジェクトの場合: 安定性と変更の少なさを重視するなら、デフォルトで v2 を選んでください。アルファ版であることを許容できる長期運用の新規アプリには v3 を推奨します。アーキテクチャが優れており(マルチウィンドウ、サービス、透明性の高いビルド)、今後の主流になるためです。トレードオフを 1 文で説明し、go.mod には正確なアルファ版のバージョンを固定してください。v3 を安定版として紹介してはいけません。

既存コードに両方の列の API が含まれている場合、 それが不具合です。他の作業に着手する前に指摘してください。


Wails v2(安定版)

標準的な main.go
//go:embed all:frontend/dist
var assets embed.FS

func main() {
    app := NewApp()

    err := wails.Run(&options.App{
        Title:  "myapp",
        Width:  1024,
        Height: 768,
        AssetServer: &assetserver.Options{Assets: assets},
        OnStartup:  app.startup,
        Bind: []interface{}{app},
    })
    if err != nil {
        log.Fatal(err)
    }
}

embed ディレクティブは all:frontend/dist です。Vite が先頭にアンダースコアの付いたファイルを出力する場合、それらを含めるには all: プレフィックスが必要です。

コンテキストを取得するパターン

v2 のランタイムで必要なコンテキストはすべて、OnStartup に渡されます。これを保存してください。これは、すべての v2 アプリを支える基本的な慣用パターンです。

type App struct {
    ctx context.Context
}

func (a *App) startup(ctx context.Context) {
    a.ctx = ctx // required for all runtime calls
}

func (a *App) OpenFile() (string, error) {
    return runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{})
}
  • OnStartup が呼び出される前に runtime.* を呼び出してはいけません — まだコンテキストが存在しません。これは v2 でよくある起動時クラッシュの原因です。
  • ここでの runtime は github.com/wailsapp/wails/v2/pkg/runtime です — ウィンドウ制御、ダイアログ、イベント、クリップボード、メニューを扱います。
バインディングとイベント
  • バインドされた構造体のエクスポート済みメソッドは、wailsjs/go/main/App の下に非同期の JS 関数として生成されます。Go の (value, error) 戻り値は、解決または拒否される Promise になります。
  • Go → JS:runtime.EventsEmit(a.ctx, "name", data) を使用します。JS 側では wailsjs/runtime の EventsOn("name", cb) を使用します。
  • バインドする構造体は薄いアダプターにしてください。ビジネスロジックは、Wails のインポートを一切含まない独立したパッケージに置きます(cobra-viper スキルの cmd/ と同じルールです)。
v2 でよくある間違い
  • 起動前にランタイム関数を呼び出す(コンテキストが nil または無効)。
  • embed ディレクティブに all: を付け忘れる — 本番ビルドでアセットがひそかに欠落します。
  • 生成された wailsjs/ ファイルを編集する — wails dev / wails build のたびに再生成されます。
  • 構造体を値でバインドする(Bind: []interface{}{App{}})— 状態が保持されるよう、ポインターをバインドしてください。

Wails v3(アルファ版)

標準的な main.go
//go:embed all:frontend/dist
var assets embed.FS

func main() {
    app := application.New(application.Options{
        Name: "myapp",
        Assets: application.AssetOptions{
            Handler: application.AssetFileServerFS(assets),
        },
        Services: []application.Service{
            application.NewService(NewGreetService()),
        },
    })

    app.Window.NewWithOptions(application.WebviewWindowOptions{
        Title: "myapp",
    })

    if err := app.Run(); err != nil { // blocks; must run on the main goroutine
        log.Fatal(err)
    }
}

Manager API スタイルを使用してください — app.Window.NewWithOptions、app.Event.On、app.Menu.New()、app.SystemTray.New()。初期のアルファ版ではフラットなメソッド(app.NewWebviewWindowWithOptions、app.OnEvent)が使われていました。チュートリアルや LLM の学習データには、それらが多数含まれています。メソッドが見つからない場合は、manager 配下に移動した可能性があります。推測で作り出すのではなく、変更履歴を確認してください。

サービス:v3 のバインディングモデル

サービスは v2 の Bind に代わるものです。サービスは単純な構造体で、エクスポートされたメソッドがバインドされます。また、任意のライフサイクルメソッドを2つ実装して、アプリにフックできます。

type NoteService struct {
    db *sql.DB
    mu sync.RWMutex
}

func (s *NoteService) ServiceStartup(ctx context.Context, opts application.ServiceOptions) error {
    // open resources, run migrations, start background goroutines governed by ctx
    return nil // returning error aborts app startup
}

func (s *NoteService) ServiceShutdown() error {
    return s.db.Close() // services shut down in reverse registration order
}

func (s *NoteService) Save(n Note) error { ... } // callable from JS
  • サービスはすべてのウィンドウで共有されるシングルトンです。可変状態はミューテックスで保護してください。
  • 依存関係は通常のコンストラクターを通じて渡します(application.NewService(NewNoteService(db, logger)))。DI フレームワークは不要です。
  • サービスは http.Handler を実装し、application.NewServiceWithOptions(svc, application.ServiceOptions{Route: "/files"}) に登録することで、HTTP に対応できます。
  • v2 と同じく、サービスは薄いアダプターです。ドメインロジックはテスト可能なように、Wails に依存しないパッケージに置きます。
バインディング、イベント、ウィンドウ
  • wails3 generate bindings でフロントエンドのバインディングを生成します(wails3 dev の実行時に自動生成されます)。wailsjs/ ではなく、frontend/bindings/<full-go-import-path>/<service> からインポートしてください。
  • イベント:app.Event.Emit("name", data) / app.Event.On("name", handler)。OS レベルのイベントは app.Event.OnApplicationEvent(events.Common.ApplicationStarted, ...) を使います。キャンセル可能なフック:window.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { e.Cancel() })。これは標準的な「閉じる前に確認する」パターンです。
  • マルチウィンドウは標準機能です。必要な数の WebviewWindow を作成でき、それぞれを個別に設定できます。
ビルドシステム

v3 のビルドは Taskfile.yml を介して go-task が調整します。アイコン生成、マニフェスト、パッケージ化は、魔法のように隠された処理ではなく、確認・編集可能なタスクステップです。CLI と格闘するのではなく、タスクを編集してカスタマイズしてください。プラットフォームごとのパッケージ化には wails3 package を使います(macOS では .app/dmg、Windows では NSIS、Linux では AppImage/deb)。

エージェント機能の追加要素:WAILS_MCP=1 を指定してビルドすると MCP サーバーが埋め込まれ、LLM エージェント(Claude を含む)が実行中のアプリを操作できます。ウィンドウの制御、DOM の検査、バインドされたメソッドの呼び出しが可能で、開発中の自動テストに非常に役立ちます。

v3 アルファ版での注意点
  • go.mod でアルファ版のバージョンを固定し、変更履歴(v3.wails.io/changelog)を確認しながら、意図的にアップグレードしてください。ナイトリーアルファ版では API 名が変更されることがあります。
  • v3 の API 呼び出しがコンパイルエラーになり、修正方法が明らかでない場合は、推測する前に最新のドキュメントを確認してください。学習データは意図的にアルファ版に追いついていません。

バージョン混在の兆候(見つけたら却下)

  • v3 プロジェクトでの runtime.EventsEmit(ctx, ...) または pkg/runtime のインポート → v2 の API です。app.Event.Emit を使ってください。
  • v2 プロジェクトでの application.New(...) または pkg/application → v3 の API です。wails.Run(&options.App{...}) を使ってください。
  • v3 でのフロントエンドからの wailsjs/go/... のインポート(正しくは frontend/bindings/...)、またはその逆。
  • v3 プロジェクトで wails dev を実行する、または v2 で wails3 dev を実行する。
  • application.Options 内の Bind: フィールド、または options.App 内の Services:。それぞれ、対応するバージョンでのみ使用します。

共通の原則(両バージョン)

  • フロントエンドからの入力は信頼できません。バインドされたメソッドの引数は HTTP ハンドラーと同じように検証してください。フロントエンドから渡された文字列をそのまま使って、シェルコマンドやファイルパスを組み立てないでください。
  • バインドされたメソッドからエラーを返してください(エラーメッセージを含む Promise の拒否になります)。パニックを起こしたり、エラーを握りつぶしたりしないでください。
  • シークレットは Go 側に保管してください。frontend/dist に含まれるものはすべてユーザーが読み取れます。
  • バインドされたメソッドで時間のかかる処理を実行すると、UI ではなく JS の Promise がブロックされます。ただし、フロントエンドからポーリングさせるのではなく、進捗イベントを発行してください。

コメント