Claude Media
Claude CodeでTauriアプリを開発する — 環境構築からRust連携まで

Claude CodeでTauriアプリを開発する — 環境構築からRust連携まで

Claude CodeでTauriアプリを開発する手順を、環境構築・プロジェクト作成からRustとフロントエンドの連携、配布まで扱います。

Tauriとは何か — Claude Codeで組む理由

Tauriは、Rustで書いたバックエンドとWeb技術のフロントエンドを組み合わせて、軽量なデスクトップ・モバイルアプリを作るフレームワークです。フロントエンドはReact・Vue・Svelteなど任意のフレームワークを使え、HTML・CSS・JavaScriptにコンパイルできれば組み込めます。

Tauriの強みは3つです。Rustのメモリー安全性を土台にした基盤、OSに標準搭載されたWebViewを使うことでの小さなバイナリサイズ、そして任意のフロントエンドを選べる柔軟なアーキテクチャです。公式ドキュメントでは、最小構成のTauriアプリは600KB未満に収まるとされています。Electronのようにブラウザーエンジンをアプリごとに同梱しない設計が理由です。

Claude Codeとの相性が良いのは、TauriプロジェクトがRustとJavaScript/TypeScriptの2言語にまたがるためです。バックエンドはsrc-tauri/配下のRustコード、フロントエンドはプロジェクトルートのJS/TSコードと、役割が物理的に分かれています。Claude Codeは両方のファイルを同時に読み書きでき、cargoやnpmのコマンドもBashツールから直接実行できます。

開発環境の前提条件

Tauriの開発にはRustのインストールが必須です。rustup経由でインストールし、OSごとに追加の依存が必要になります。

OS追加で必要なもの
macOS追加で必要なものXcode(デスクトップのみならCommand Line Toolsで可)
Windows追加で必要なものMicrosoft C++ Build Tools(Desktop development with C++)+ WebView2(Windows 10の1803以降は導入済み)
Debian/Ubuntu追加で必要なものlibwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
Arch Linux追加で必要なものwebkit2gtk-4.1 base-devel curl wget など

Linuxは配布元ごとにパッケージ名が違います。前提条件のページにはFedora・Gentoo・openSUSE・Alpine・NixOS向けのコマンドも別々に載っているので、Debian系以外はそちらの一覧をそのままClaude Codeに渡します。

Claude Codeにこれらのインストールコマンドを実行させる場合、aptやbrew、Xcodeのライセンス同意といった管理者権限を要する操作が混じります。Bashツールの許可設定を事前に確認し、対話式のプロンプトが出た場合は手動での承認を挟む前提で進めます。

xcode-select --install

Claude CodeでTauriプロジェクトを作成する

環境が整ったら、公式のスキャフォールディングツールcreate-tauri-appでプロジェクトを作成します。対話式にフロントエンドのテンプレートを選べます。公式テンプレートはVanilla・Vue.js・Svelte・React・SolidJS・Angular・Preact・Yew・Leptos・Sycamoreに対応しています。

npm create tauri-app@latest

作成されたプロジェクトは、ルート直下のJavaScriptプロジェクトとsrc-tauri/内のRustプロジェクトの2階層構成になります。src-tauri/にはCargo.toml、Tauriの設定ファイルtauri.conf.json、アイコン一式を置くicons/、そしてIPC(プロセス間通信)の許可設定を置くcapabilities/が含まれます。

開発サーバーは次のコマンドで起動します。tauri devはbuild.beforeDevCommandでフロントエンドのdevサーバーを起動し、build.devUrlを表示するネイティブのウィンドウを開きます。

npm run tauri dev

Claude Codeにこの構成でコードを書かせるときは、CLAUDE.mdに「Rustのコマンド実装はsrc-tauri/src/lib.rs、フロントエンドのUIはsrc/」のように役割を明記しておくと、編集対象を取り違えにくくなります。

既存プロジェクトへの追加とモバイル対応

すでにあるWebアプリをTauri化したい場合は、create-tauri-appで新規プロジェクトを作らずに、既存のコードベースへTauriを追加する経路も用意されています。フロントエンド側の構成はそのままに、src-tauri/だけを後付けする形です。

モバイル向けのビルドも同じCLIから扱えます。tauri android initでAndroidターゲットを初期化し、tauri android devで実機・エミュレーターに向けた開発モードを起動します。iOS向けはtauri ios initとtauri ios devが対応します。

モバイル開発の前提は、デスクトップとは別です。AndroidはAndroid StudioのインストールとJAVA_HOME環境変数の設定が要り、iOSはXcodeのフルインストールが要ります。

環境まわりで原因が分からないエラーに当たったときは、tauri infoコマンドが役立ちます。Rust・Node.jsのバージョンやプロジェクト設定を一覧表示するので、Claude Codeに原因調査をさせる際は、最初にこの出力を渡すと切り分けが早くなります。

Rustコマンドを書かせるとき、どこで詰まるか

TauriのIPCは、Rust側で#[tauri::command]を付けた関数を、フロントエンドのJavaScriptからinvoke()で呼び出す形です。Rustの関数とJS側の呼び出しが別ファイルに分かれるので、Claude Codeに書かせたコードがビルドは通るのに動かない、という場面が起きます。公式のIPCガイドが挙げる落とし穴は、次の4つです。

落とし穴

invokeまわりで詰まる4つの型

  • lib.rsのコマンドにpubを付ける

    lib.rsに定義するコマンドはpubにできません。付けると__cmd__command_nameが二重定義だというE0255エラーになります。別モジュールに置く場合は逆にpubが必要で、generate_handler!にはcommands::my_custom_commandのようにパスで渡します。

  • 引数のキーはcamelCase

    Rust側がinvoke_messageでも、JS側は{ invokeMessage: 'Hello!' }と書きます。Rust側を#[tauri::command(rename_all = "snake_case")]にすれば、JS側もsnake_caseにできます。

  • エラー型がSerializeを実装していない

    戻り値に使う型はserde::Serializeを実装している必要があり、std::io::Errorなどの標準ライブラリのエラー型は実装していません。簡易にはmap_err(|err| err.to_string())で文字列にします。thiserrorで独自のエラー型を作る方法も示されています。

  • asyncコマンドに借用引数を置く

    async fnの引数に&strやState<'_, Data>のような借用型を置くことは、現状できません。Stringに変えるか、戻り値をResultにします。

asyncを付けないコマンドはメインスレッドで動きます。重い処理を同期コマンドに書かせるとUIが固まるので、時間のかかる処理はasyncにするか#[tauri::command(async)]を付けます。大きなファイルを返す場合は、JSONにシリアライズされて遅くなるのを避けるため、tauri::ipc::Responseで返す方法があります。

コマンドを足すときは、#[tauri::command]を付けた関数だけでは足りず、tauri::Builderのinvoke_handlerにgenerate_handler!で登録する必要があります。登録を忘れるとinvoke()は失敗します。

手順

新しいRustコマンドを足す順番

  1. 1

    Rustの関数を書く

    #[tauri::command]を付けた関数をsrc-tauri/src/lib.rs、または別モジュールに追加します。

  2. 2

    ハンドラーに登録する

    invoke_handler(tauri::generate_handler![...])の配列にコマンド名を足します。

  3. 3

    フロントエンドから呼ぶ

    @tauri-apps/api/coreのinvokeでコマンド名を呼びます。引数と戻り値の型を、Rust側のシグネチャに合わせます。

capabilitiesはいつ要るのか

プロジェクト構成のページには、capabilities/で許可しないとコマンドをJavaScriptから使えないという簡略な説明があります。自作コマンドには当てはまりません。公式のcapabilitiesのページによると、invoke_handlerに登録したコマンドは、既定ではアプリのすべてのウィンドウとWebViewから使えます。許可を絞りたいときは、src-tauri/build.rsのAppManifest::commandsで自作コマンドを列挙します。

くらべる

capabilitiesで許可が要るもの・要らないもの

許可の追記なし

既定で呼べる

invoke_handlerに登録した自作のRustコマンド。

capabilityで許可

permissionsに書く

core:window:allow-set-titleのようなコアAPIの権限と、dialog:openなどのプラグインの権限。

capabilityファイルはsrc-tauri/capabilities/にJSONかTOMLで置きます。公式の例は次の構造で、windowsに対象ウィンドウのラベル、permissionsに許可する権限を並べます。

{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "main-capability",
  "description": "Capability for the main window",
  "windows": ["main"],
  "permissions": [
    "core:window:default",
    "core:window:allow-set-title"
  ]
}

ここで見落としやすいのが、ファイルの有効化のルールです。capabilities/内のファイルは、既定ですべて有効になります。ところがtauri.conf.jsonのapp.security.capabilitiesに1つでも識別子を書くと、そこに書いたものだけがビルドに使われます。Claude Codeに新しいcapabilityファイルを足させたのに権限エラーが消えないときは、tauri.conf.json側の列挙に識別子が入っているかを見ます。

Claude Codeに権限まわりを任せるときは、次の点も押さえておきます。

  • 同じウィンドウが複数のcapabilityに入っていると、各capabilityの許可は合算されます。
  • 境界を決めるのはウィンドウのラベルで、タイトルではありません。
  • capabilityが守るのはフロントエンド経由の露出で、Rust側のコードの不備や緩すぎるスコープは守備範囲外です。

Rustコマンドの本体に書くファイル操作などは、Claude Codeが生成したコードをそのまま信頼せず、レビューの対象にします。

CLAUDE.mdには、「Rustコマンドを追加したらgenerate_handler!への登録とフロントエンドの呼び出しも同じ変更に含める」と書いておくのが実用的です。フロントエンドの型定義(invoke<T>()の戻り値型)とRust側の関数シグネチャがずれるケースも、両方を1つの編集単位として指示すると防ぎやすくなります。

Rust側のコンパイルエラーが読みにくいときは、デバッグ環境のガイドが公式ドキュメントにあります。VS Code・JetBrains IDE(RustRoverなど)・Neovim向けが個別に用意されています。エディター側のデバッガーとTauriプロジェクトを接続する手順がまとまっています。

バイナリサイズをさらに詰めたい場合は、src-tauri/Cargo.tomlにリリース用プロファイルを追加します。

[profile.release]
codegen-units = 1
lto = true
opt-level = "s"
panic = "abort"
strip = true

codegen-units = 1とlto = trueでリンク時最適化を有効にし、opt-level = "s"でサイズ優先のコンパイルに切り替えます。strip = trueでデバッグシンボルを取り除く設定です。

作り始める前に画面構成やRustコマンドの一覧を整理しておきたい場合は、cc-sddでClaude Codeの仕様駆動開発を実践するのような仕様駆動の進め方も選択肢になります。フロントエンド部分だけを先に確認したいときは、devサーバーが通常のlocalhostである性質を利用して、Claude Code DesktopアプリプレビューでWebアプリを検証するの手順でブラウザー側から動作を見ることもできます。

よくあるつまずき

cargoコマンドが見つからない

Rustはrustup経由でインストールし、シェルを再起動してPATHを反映させる必要があります。Claude Codeのセッションを開き直さないとPATHの変更が反映されないこともあります。

Linuxでビルドエラーになる

ディストリビューションによってwebkit2gtk系パッケージの名前が異なります。Debian/Ubuntu系はlibwebkit2gtk-4.1-dev、Arch Linuxはwebkit2gtk-4.1です。Claude CodeでCI・サンドボックス環境のビルドを自動化する際は、ベースイメージのディストリビューションを先に確認し、前提条件のページから該当する一覧を引きます。

フロントエンドからinvoke()が失敗する

まず、上の4つの型とgenerate_handler!への登録漏れを順に疑います。コアAPIやプラグインを呼ぶ場合は、capabilities/に権限があり、tauri.conf.jsonのapp.security.capabilitiesにも識別子が並んでいるかを確かめます。

WindowsでWebView2関連のエラーが出る

Windows 10のビルド1803より前の環境では、WebView2ランタイムが導入されていないことがあります。その場合はWebView2ランタイムを別途インストールします。

devUrlの設定漏れでウィンドウに画面が表示されない

フロントエンドのdevサーバーのURLをtauri.conf.jsonのbuild.devUrlに指定していないと、Tauriがどこを表示すればよいか分かりません。フレームワーク側のポート番号と一致させます。

配布用ビルドを作る

tauri buildはリリースモードでのビルドと、プラットフォームごとのインストーラー生成を一括で行います。生成されるバンドル形式はOSごとに違い、WindowsはmsiとNSISの-setup.exe、macOSはdmg、Linuxはdebやappimageなどです。msiはWindows上でのみ生成できます。

バンドル生成だけを個別に制御したい場合は、ビルドとバンドルの手順を分けられます。tauri build --no-bundleでビルドのみ実行し、tauri bundleでバンドルだけをやり直せます。形式は--bundlesで指定します。DMGならMac上でtauri build --bundles dmgと実行します。

ほとんどのプラットフォームはコード署名を要求します。署名がないと、WindowsではSmartScreenの警告が、macOSでは壊れていて開けない旨の警告が出ることがあります。証明書の取得・設定は配布計画の初期段階から見込んでおく必要があります。

用途別の向き不向き

シーン向き不向き理由
軽量な配布物が要る社内ツール向き不向き向いている理由最小構成で600KB未満のバイナリに収まる設計
既存のReact/Vue資産の転用向き不向き向いている理由フロントエンドはそのまま流用できる
モバイル(iOS/Android)展開も視野向き不向き条件次第理由Tauri 2はモバイルターゲットに対応するが、Xcode・Android SDK等の追加設定が要る
Rust未経験のチームでの急ぎの開発向き不向き慎重に理由バックエンドロジックをRustで書く前提のため学習コストがかかる

まとめ

invoke()が失敗したときは、自作コマンドならRust側の登録や型の問題、コアAPIやプラグインなら権限の問題と分けて疑うと、原因に早く届きます。tauri infoの出力とinvoke()のエラー文をそのままClaude Codeに渡すのが、最初の一手です。Claude Codeを使った開発ツールの導入事例はClaude Code開発ツール導入事例で扱っています。

この記事を共有:XはてブLinkedIn