jpskill.com
🛠️ 開発・MCP コミュニティ

wails

Go言語でバックエンドを、React/Vue/SvelteなどのWeb技術でフロントエンドを構築し、軽量かつ高速なデスクトップアプリを開発できるWailsフレームワークについて、TypeScriptバインディングを通じて開発者を支援するSkill。

📜 元の英語説明(参考)

Expert guidance for Wails, the Go framework for building desktop applications with web frontends. Helps developers build lightweight, fast desktop apps where the backend is Go and the frontend is any web framework (React, Vue, Svelte), communicating through auto-generated TypeScript bindings.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Go言語でバックエンドを、React/Vue/SvelteなどのWeb技術でフロントエンドを構築し、軽量かつ高速なデスクトップアプリを開発できるWailsフレームワークについて、TypeScriptバインディングを通じて開発者を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o wails.zip https://jpskill.com/download/15548.zip && unzip -o wails.zip && rm wails.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15548.zip -OutFile "$d\wails.zip"; Expand-Archive "$d\wails.zip" -DestinationPath $d -Force; ri "$d\wails.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して wails.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → wails フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Wails — Go と Web フロントエンドによるデスクトップアプリケーション

概要

Wails は、Web フロントエンドでデスクトップアプリケーションを構築するための Go フレームワークです。開発者が軽量で高速なデスクトップアプリケーションを構築するのに役立ちます。バックエンドは Go であり、フロントエンドは任意の Web フレームワーク (React, Vue, Svelte) であり、自動生成された TypeScript バインディングを通じて通信します。

手順

プロジェクトのセットアップ

# Wails CLI をインストール
go install github.com/wailsapp/wails/v2/cmd/wails@latest

# システムの依存関係をチェック
wails doctor

# 新しいプロジェクトを作成 (React + TypeScript)
wails init -n my-app -t react-ts
cd my-app

# 開発モード (フロントエンド + バックエンドのホットリロード)
wails dev

# 本番用バイナリをビルド
wails build                         # build/bin/ に出力
wails build -platform darwin/amd64  # クロスコンパイル
wails build -nsis                   # Windows インストーラ

Go バックエンド

// app.go — フロントエンドに公開されるメソッドを持つアプリケーションバックエンド
// App 構造体のメソッドは、JavaScript から自動的に呼び出し可能になります。

package main

import (
    "context"
    "database/sql"
    "fmt"
    "os"
    "path/filepath"

    _ "modernc.org/sqlite"
)

// App 構造体 — エクスポートされたメソッドはすべてフロントエンドで使用可能になります
type App struct {
    ctx context.Context
    db  *sql.DB
}

// startup はアプリの起動時に呼び出されます — ここでリソースを初期化します
func (a *App) startup(ctx context.Context) {
    a.ctx = ctx

    // ユーザーのアプリデータディレクトリに SQLite データベースを開きます
    homeDir, _ := os.UserHomeDir()
    dbPath := filepath.Join(homeDir, ".my-app", "data.db")
    os.MkdirAll(filepath.Dir(dbPath), 0755)

    db, err := sql.Open("sqlite", dbPath)
    if err != nil {
        fmt.Printf("Failed to open database: %v\n", err)
        return
    }
    a.db = db

    // テーブルを作成
    a.db.Exec(`CREATE TABLE IF NOT EXISTS notes (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        content TEXT NOT NULL DEFAULT '',
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
    )`)
}

// Note はデータモデルです — 型付き TypeScript インターフェースとしてフロントエンドに返されます
type Note struct {
    ID        int64  `json:"id"`
    Title     string `json:"title"`
    Content   string `json:"content"`
    CreatedAt string `json:"createdAt"`
    UpdatedAt string `json:"updatedAt"`
}

// GetNotes はすべてのノートを返します — フロントエンドから GetNotes() として呼び出し可能
func (a *App) GetNotes() ([]Note, error) {
    rows, err := a.db.Query("SELECT id, title, content, created_at, updated_at FROM notes ORDER BY updated_at DESC")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var notes []Note
    for rows.Next() {
        var n Note
        rows.Scan(&n.ID, &n.Title, &n.Content, &n.CreatedAt, &n.UpdatedAt)
        notes = append(notes, n)
    }
    return notes, nil
}

// CreateNote は新しいノートを作成します — フロントエンドは CreateNote(title) を呼び出します
func (a *App) CreateNote(title string) (*Note, error) {
    result, err := a.db.Exec("INSERT INTO notes (title) VALUES (?)", title)
    if err != nil {
        return nil, err
    }
    id, _ := result.LastInsertId()
    return &Note{ID: id, Title: title, Content: ""}, nil
}

// UpdateNote はノートの内容を保存します — 編集のたびに呼び出されます
func (a *App) UpdateNote(id int64, title, content string) error {
    _, err := a.db.Exec(
        "UPDATE notes SET title = ?, content = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?",
        title, content, id,
    )
    return err
}

// DeleteNote はノートを削除します
func (a *App) DeleteNote(id int64) error {
    _, err := a.db.Exec("DELETE FROM notes WHERE id = ?", id)
    return err
}

// OpenFile はネイティブファイルダイアログを開き、ファイルの内容を返します
func (a *App) OpenFile() (string, error) {
    selection, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
        Title: "Open File",
        Filters: []runtime.FileFilter{
            {DisplayName: "Text Files", Pattern: "*.txt;*.md"},
        },
    })
    if err != nil {
        return "", err
    }
    data, err := os.ReadFile(selection)
    return string(data), err
}

フロントエンド (React + TypeScript)

// frontend/src/App.tsx — 自動生成されたバインディングを持つ React フロントエンド
// Wails は Go の構造体と関数から TypeScript の型を生成します。

import { useState, useEffect } from "react";
// これらのインポートは、Wails によって Go コードから自動生成されます
import { GetNotes, CreateNote, UpdateNote, DeleteNote } from "../wailsjs/go/main/App";
import { main } from "../wailsjs/go/models";

function App() {
  const [notes, setNotes] = useState<main.Note[]>([]);
  const [selectedNote, setSelectedNote] = useState<main.Note | null>(null);

  useEffect(() => {
    loadNotes();
  }, []);

  async function loadNotes() {
    const result = await GetNotes();       // Go メソッドを呼び出し、型付きの Note[] を返します
    setNotes(result || []);
  }

  async function handleCreate() {
    const note = await CreateNote("Untitled");  // Go は *Note を返し、TS は main.Note を取得します
    if (note) {
      setNotes([note, ...notes]);
      setSelectedNote(note);
    }
  }

  async function handleSave(id: number, title: string, content: string) {
    await UpdateNote(id, title, content);  // Go を呼び出し、SQLite に保存します
    loadNotes();
  }

  async function handleDelete(id: number) {
    await DeleteNote(id);
    setSelectedNote(null);
    loadNotes();
  }

  return (
    <div className="app">
      <aside className="sidebar">
        <button onClick={handleCreate}>+ New Note</button>
        <ul>
          {notes.map((note) => (
            <li
              key={note.id}
              className={selectedNote?.id === note.id ? "active" : ""}
              onClick={() => setSelectedNote(note)}
            >
              <strong>{note.title}</strong>
              <small>{note.updatedAt}</small>
            </li>
          ))}
        </ul>
      </aside>

      <main className="editor">
        {selectedNote ? (
          <NoteEditor
            note={selectedNote}
            onSave={handleSave}
            onDelete={handleDelete}
          />
        ) : (
          <p>Select or create a note</p>
        )}
      </main>
    </div>
  );
}

システムトレイとメニュー

// main.go — ネイティブメニューとシステムトレイ
package main



(原文がここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Wails — Desktop Apps with Go and Web Frontend

Overview

Wails, the Go framework for building desktop applications with web frontends. Helps developers build lightweight, fast desktop apps where the backend is Go and the frontend is any web framework (React, Vue, Svelte), communicating through auto-generated TypeScript bindings.

Instructions

Project Setup

# Install Wails CLI
go install github.com/wailsapp/wails/v2/cmd/wails@latest

# Check system dependencies
wails doctor

# Create a new project (React + TypeScript)
wails init -n my-app -t react-ts
cd my-app

# Development mode (hot reload for frontend + backend)
wails dev

# Build production binary
wails build                         # Outputs to build/bin/
wails build -platform darwin/amd64  # Cross-compile
wails build -nsis                   # Windows installer

Go Backend

// app.go — Application backend with methods exposed to frontend
// Methods on the App struct are automatically callable from JavaScript.

package main

import (
    "context"
    "database/sql"
    "fmt"
    "os"
    "path/filepath"

    _ "modernc.org/sqlite"
)

// App struct — any exported method becomes available in the frontend
type App struct {
    ctx context.Context
    db  *sql.DB
}

// startup is called when the app starts — initialize resources here
func (a *App) startup(ctx context.Context) {
    a.ctx = ctx

    // Open SQLite database in user's app data directory
    homeDir, _ := os.UserHomeDir()
    dbPath := filepath.Join(homeDir, ".my-app", "data.db")
    os.MkdirAll(filepath.Dir(dbPath), 0755)

    db, err := sql.Open("sqlite", dbPath)
    if err != nil {
        fmt.Printf("Failed to open database: %v\n", err)
        return
    }
    a.db = db

    // Create tables
    a.db.Exec(`CREATE TABLE IF NOT EXISTS notes (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT NOT NULL,
        content TEXT NOT NULL DEFAULT '',
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
    )`)
}

// Note is a data model — returned to frontend as typed TypeScript interface
type Note struct {
    ID        int64  `json:"id"`
    Title     string `json:"title"`
    Content   string `json:"content"`
    CreatedAt string `json:"createdAt"`
    UpdatedAt string `json:"updatedAt"`
}

// GetNotes returns all notes — callable from frontend as GetNotes()
func (a *App) GetNotes() ([]Note, error) {
    rows, err := a.db.Query("SELECT id, title, content, created_at, updated_at FROM notes ORDER BY updated_at DESC")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var notes []Note
    for rows.Next() {
        var n Note
        rows.Scan(&n.ID, &n.Title, &n.Content, &n.CreatedAt, &n.UpdatedAt)
        notes = append(notes, n)
    }
    return notes, nil
}

// CreateNote creates a new note — frontend calls CreateNote(title)
func (a *App) CreateNote(title string) (*Note, error) {
    result, err := a.db.Exec("INSERT INTO notes (title) VALUES (?)", title)
    if err != nil {
        return nil, err
    }
    id, _ := result.LastInsertId()
    return &Note{ID: id, Title: title, Content: ""}, nil
}

// UpdateNote saves note content — called on every edit
func (a *App) UpdateNote(id int64, title, content string) error {
    _, err := a.db.Exec(
        "UPDATE notes SET title = ?, content = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?",
        title, content, id,
    )
    return err
}

// DeleteNote removes a note
func (a *App) DeleteNote(id int64) error {
    _, err := a.db.Exec("DELETE FROM notes WHERE id = ?", id)
    return err
}

// OpenFile opens a native file dialog and returns the file content
func (a *App) OpenFile() (string, error) {
    selection, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
        Title: "Open File",
        Filters: []runtime.FileFilter{
            {DisplayName: "Text Files", Pattern: "*.txt;*.md"},
        },
    })
    if err != nil {
        return "", err
    }
    data, err := os.ReadFile(selection)
    return string(data), err
}

Frontend (React + TypeScript)

// frontend/src/App.tsx — React frontend with auto-generated bindings
// Wails generates TypeScript types from Go structs and functions.

import { useState, useEffect } from "react";
// These imports are auto-generated by Wails from Go code
import { GetNotes, CreateNote, UpdateNote, DeleteNote } from "../wailsjs/go/main/App";
import { main } from "../wailsjs/go/models";

function App() {
  const [notes, setNotes] = useState<main.Note[]>([]);
  const [selectedNote, setSelectedNote] = useState<main.Note | null>(null);

  useEffect(() => {
    loadNotes();
  }, []);

  async function loadNotes() {
    const result = await GetNotes();       // Calls Go method, returns typed Note[]
    setNotes(result || []);
  }

  async function handleCreate() {
    const note = await CreateNote("Untitled");  // Go returns *Note, TS gets main.Note
    if (note) {
      setNotes([note, ...notes]);
      setSelectedNote(note);
    }
  }

  async function handleSave(id: number, title: string, content: string) {
    await UpdateNote(id, title, content);  // Calls Go, saves to SQLite
    loadNotes();
  }

  async function handleDelete(id: number) {
    await DeleteNote(id);
    setSelectedNote(null);
    loadNotes();
  }

  return (
    <div className="app">
      <aside className="sidebar">
        <button onClick={handleCreate}>+ New Note</button>
        <ul>
          {notes.map((note) => (
            <li
              key={note.id}
              className={selectedNote?.id === note.id ? "active" : ""}
              onClick={() => setSelectedNote(note)}
            >
              <strong>{note.title}</strong>
              <small>{note.updatedAt}</small>
            </li>
          ))}
        </ul>
      </aside>

      <main className="editor">
        {selectedNote ? (
          <NoteEditor
            note={selectedNote}
            onSave={handleSave}
            onDelete={handleDelete}
          />
        ) : (
          <p>Select or create a note</p>
        )}
      </main>
    </div>
  );
}

System Tray and Menus

// main.go — Native menus and system tray
package main

import (
    "embed"
    "github.com/wailsapp/wails/v2"
    "github.com/wailsapp/wails/v2/pkg/menu"
    "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() {
    app := &App{}

    appMenu := menu.NewMenu()
    fileMenu := appMenu.AddSubmenu("File")
    fileMenu.AddText("New Note", keys.CmdOrCtrl("n"), func(_ *menu.CallbackData) {
        // Emit event to frontend
        runtime.EventsEmit(app.ctx, "menu:new-note")
    })
    fileMenu.AddSeparator()
    fileMenu.AddText("Quit", keys.CmdOrCtrl("q"), func(_ *menu.CallbackData) {
        runtime.Quit(app.ctx)
    })

    err := wails.Run(&options.App{
        Title:     "My Notes",
        Width:     1024,
        Height:    768,
        MinWidth:  600,
        MinHeight: 400,
        AssetServer: &assetserver.Options{
            Assets: assets,
        },
        OnStartup: app.startup,
        Menu:      appMenu,
        Bind:      []interface{}{app},
    })
    if err != nil {
        panic(err)
    }
}

Installation

# Prerequisites: Go 1.21+, Node.js 16+
go install github.com/wailsapp/wails/v2/cmd/wails@latest

# macOS also needs Xcode command line tools
xcode-select --install

# Linux needs webkit2gtk
sudo apt install libgtk-3-dev libwebkit2gtk-4.0-dev

Examples

Example 1: Setting up Wails with a custom configuration

User request:

I just installed Wails. Help me configure it for my TypeScript + React workflow with my preferred keybindings.

The agent creates the configuration file with TypeScript-aware settings, configures relevant plugins/extensions for React development, sets up keyboard shortcuts matching the user's preferences, and verifies the setup works correctly.

Example 2: Extending Wails with custom functionality

User request:

I want to add a custom go backend to Wails. How do I build one?

The agent scaffolds the extension/plugin project, implements the core functionality following Wails's API patterns, adds configuration options, and provides testing instructions to verify it works end-to-end.

Guidelines

  1. Go for backend, web for UI — Keep business logic, file I/O, database access in Go; keep UI rendering in the frontend
  2. Auto-generated bindings — Never write API boilerplate; Wails generates TypeScript types from Go structs automatically
  3. Embed assets — Use //go:embed to bundle the frontend into the binary; single-file distribution
  4. Events for async — Use runtime.EventsEmit for Go→frontend communication (progress updates, background task results)
  5. Native dialogs — Use Wails' runtime dialogs (file picker, message box) instead of HTML modals for native feel
  6. SQLite for local data — Ship with SQLite for offline-first apps; it's a single file in the user's app data directory
  7. Dev mode for iterationwails dev provides hot reload for both Go and frontend; iterate fast
  8. Cross-compile — Build for all platforms from one machine with wails build -platform; test on each OS before release