6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Tauri 2.0 に入門する

6
Last updated at Posted at 2025-11-27

こんにちは!
最近、クロスプラットフォーム開発への興味が湧いてきました。

そこで、以前から気になっていた 「Tauri 2.0」 を触ってみることにしました。
これまで「Web技術で作るデスクトップアプリ開発」といえば、Electron一強のイメージでしたが、2024年にメジャーアップデートされた Tauri 2.0 ではモバイル対応(iOS/Android)も強化されたとのこと。

「Rust は難しそう・・・」と少し身構えていたのですが、実際に触ってみるとフロントエンドの知識(Vue や React)がそのまま活かせて、意外とサクッと入門できました。
今回は、環境構築からプロジェクト作成、そして実際に動かすところまでの記録をお届けします。

そもそも「Tauri 2.0」って何?

ざっくり言うと、 「Web技術(HTML/JS/CSS)で作れる、超軽量で安全なアプリ開発ツール」 です。
見た目を作るフロントエンドはおなじみの React や Vue などを使い、システムに関わるバックエンド部分を Rust が担当します。

なんでTauriが注目されているの?

難しい話は抜きにして、ポイントは3つあると思っています。

  1. とにかく軽い!
    • Electron はブラウザ(Chromium)を丸ごと抱え込むためサイズが大きくなりがちですが、Tauri は OS 標準の WebView を借りて動くので、アプリのサイズが劇的に小さくなります
  2. Web の知識がそのまま使える
    • 普段 Web 開発をしている人なら、学習コストを抑えてネイティブアプリ開発に着手できます
  3. 2.0 からモバイル対応が本格化
    • デスクトップだけでなく、iOS や Android アプリも視野に入れて開発できるようになりました

Electron や Flutter との違いは?

クロスプラットフォームといえば、ElectronFlutterReact Nativeといった候補があるかと思います。
「結局どれを使えばいいの?」と迷うところですが、私の理解ではこんなイメージです。

  • Electron: 実績豊富で何でもできるけど、配布サイズや実行時の使用メモリ量が多くなりがち
  • Flutter: スマホアプリに強く UI も綺麗だけど、Dart 言語の習得が必要
  • React Native: モバイル中心にネイティブUIを扱えるが、デスクトップ対応は選択肢が限られる
  • Tauri 2.0: 「Web 技術を活かしたい」かつ「軽快なアプリを作りたい」 人にピッタリ

早速プロジェクトを作ってみる!

今回は Windows 環境で試してみました。
事前に公式の前提条件に沿って、Node.jsRustMicrosoft C++ Build Toolsなどを準備しておきます。

今回の検証環境(本記事作成時点)

  • OS: Windows 11
  • Node.js: 24.11.1
  • npm: 11.6.2
  • Rust: 1.91.1
    • cargo: 1.91.1
    • rustc: 1.91.1
    • rustdoc: 1.91.1
  • Microsoft C++ Build Tools: インストール済み

準備ができたら、公式のQuick Startに書かれているコマンドを1つ叩くだけです。
Tauri 2.0のプロジェクトはBashPowerShellnpmFishYarnpnpmdenobunCargoでプロジェクトを作成することができるようです。
今回はnpmでプロジェクトを作成しました。

npm create tauri-app@latest

すると、対話形式でいくつか質問されます。
英語で聞かれますが、基本的には好きなものを選ぶだけなので怖くありません。今回は社内の技術スタックに合わせて Vue + TypeScript の構成にしてみました。

実際のやり取りはこんな感じです。

  1. 追加パッケージのインストール確認
    • Need to install the following packages: create-tauri-app@... と表示されるので、そのまま Entery のままで OK)
  2. Project name(プロジェクト名)
    • tauri-app(デフォルトのまま Enter!)
  3. Identifier(識別子)
    • com.my_name.tauri-app(これもデフォルトで Enter!)
    • 自分のドメイン風の文字列に変えても構いません。
  4. Choose which language to use for your frontend(フロントエンドの言語)
    • TypeScript / JavaScript を選択してEnter!
    • 選択肢の変更は上下キーで行えます
  5. Choose your package manager(パッケージマネージャ)
    • いつも使っているnpmを選択してEnter!
  6. Choose your UI template(UIテンプレート)
    • 社内の技術スタックに合わせてVueを選択(React や Svelte なども選べます)
  7. Choose your UI flavor(UIフレーバー)
    • TypeScriptを選択

ここまで進むと、Tauri + Vue + TypeScript 構成のプロジェクトが自動生成されました。

ディレクトリ構成を覗いてみる

出来上がったフォルダの中身はどうなっているのでしょうか?
主要な部分だけチェックしてみます。

tauri-app/
├─ package.json
├─ vite.config.ts
├─ tsconfig.json
├─ tsconfig.node.json
├─ index.html
├─ public/
│  ├─ tauri.svg
│  └─ vite.svg
├─ src/                      # フロントエンド(Vue + Vite)
│  ├─ main.ts                # エントリポイント
│  ├─ App.vue                # 画面本体
│  └─ assets/
│     └─ vue.svg
└─ src-tauri/                # Tauri(Rust)側の設定やロジック
   ├─ Cargo.toml
   ├─ build.rs
   ├─ tauri.conf.json        # アプリの設定(ウィンドウサイズや権限など)
   ├─ capabilities/          # アプリに何を許可するか(セキュリティ設定)
   │  └─ default.json
   ├─ icons/                 # 各種アイコン
   └─ src/
      ├─ main.rs             # エントリポイント(Rust)
      └─ lib.rs              # コマンド定義と Builder 設定

構造としては非常にシンプルです。
srcフォルダで普段通りVue(フロントエンド)のコードを書き、src-tauriにバックエンドのコードを書く、という分担になっています。
これならフロントエンドエンジニアでも迷子にならずに済みそうです。

いざ、起動!

依存関係をインストールして、開発モードで起動してみます。

cd tauri-app
npm install
npm run tauri dev

少し待つと・・・・・・・
立ち上がりました!
app画面1.png
おお、普通のブラウザではなく、独立したウィンドウとしてアプリが表示されています!
Tauri と Vite と Vue のロゴが並んでいるのが誇らしいですね。

試しに名前を入力して「Greet」ボタンを押してみます。
app画面2.png

無事、Rust 側から挨拶が返ってきました!

ちなみに、配布用のインストーラーを作りたい場合はnpm run tauri buildを叩くだけ。
クロスプラットフォーム開発の敷居がグッと下がった気がします。

【ちょこっと解説】裏側では何が起きている?

「ボタンを押したら挨拶が返ってくる」という単純な動きですが、裏側ではJS(フロント)とRust(バック)の連携が行われています。
ここが Tauri 開発のキモになる部分なので、少しだけコードを覗いてみましょう。

1. Rust側(バックエンド)

src-tauri/src/lib.rsに、挨拶をする関数greetが定義されています。

#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

greet 関数は何をしているか

  • フロントエンドから渡された name(文字列)を受け取り、"Hello, {name}! You've been greeted from Rust!" という挨拶文に組み立てて返すだけのシンプルな関数です。
  • 戻り値は String 型なので、Tauri 側で JSON にシリアライズされてフロントエンドへ送り返されます。
  • 関数の上についている #[tauri::command] は「この関数を Tauri コマンドとして公開する」という印です。

invoke_handler へ greet をどう登録しているか

  • tauri::generate_handler![greet] はマクロで、"greet" というコマンド名と greet 関数本体をひも付ける「ハンドラ集合」を生成します。
  • その結果を invoke_handler(...) に渡すことで、Tauri は「フロントエンドから invoke("greet", ...) が飛んできたら、この greet 関数を呼べばいい」と認識できるようになります。
  • まとめると、#[tauri::command] で「公開対象」にし、generate_handler![greet]invoke_handler(...) で「名前付きコマンドとして登録する」という 2 段構えになっているイメージです。

2. Vue側(フロントエンド)

src/App.vueではTauri公式のライブラリ(@tauri-apps/api/coreinvoke)を使ってRustの関数を呼び出します。

src/App.vue より(抜粋):

<script setup lang="ts">
import { ref } from "vue";
import { invoke } from "@tauri-apps/api/core";

const greetMsg = ref("");
const name = ref("");

async function greet() {
  // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
  greetMsg.value = await invoke("greet", { name: name.value });
}
</script>

テンプレート側では、次のようにボタンと表示領域が定義されています(抜粋)。

<template>
  <form class="row" @submit.prevent="greet">
    <input id="greet-input" v-model="name" placeholder="Enter a name..." />
    <button type="submit">Greet</button>
  </form>
  <p>{{ greetMsg }}</p>
  <!-- 省略 -->
</template>

ここで押さえておきたいポイントは次の通りです。

  • greet ボタンと関数の対応
    • <form ... @submit.prevent="greet"> により、「フォーム送信(Greet ボタン押下)」イベントが greet 関数にひも付いています。
    • type="submit" のボタンを押すとフォーム送信イベントが発火し、ページリロードは .prevent で抑止され、その代わりに greet() が呼ばれます。
  • フロントエンド側 greet 関数は非同期
    • async function greet()await invoke(...) によって、Rust 側の処理が終わるまで待ち、その結果を greetMsg.value に代入します。
    • 非同期にしておくことで、バックエンドの処理が多少時間を要しても UI スレッドをブロックせずに済みます。
  • バックエンドからのメッセージの受け取り方
    • invoke("greet", { name: name.value }) が Rust 側の greet 関数呼び出しに対応しており、戻り値の文字列が await の結果として返ってきます。
    • その値をそのまま greetMsg.value に代入することで、「バックエンドからのメッセージ」を受け取っています。
  • メッセージの表示方法
    • テンプレート側の <p>{{ greetMsg }}</p> で、greetMsg の中身をそのまま画面にバインドしています。
    • つまり「入力 → Greet ボタン押下 → Rust の greet 関数実行 → 戻り値を greetMsg に格納 → <p> に表示」という一連の流れが、この短いコードで完結しています。

まとめ:Tauri 2.0 は「アリ」か?

今回はプロジェクト作成から起動までを試してみましたが、感想としては 「めちゃくちゃアリ」 です。

  • 環境構築が楽: コマンド一発で Vue + TypeScript 環境が整う
  • 開発体験が良い: ホットリロードも効くので、Web 開発と同じ感覚でサクサク作れる
  • Rust も怖くない: 必要なところだけ Rust を書けばいいので、少しずつ勉強しながら進められる

次回は「Tauri のコマンド」についてもう少し踏み込んでみたいと思います。


出典・参考リンク

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?