こんにちは!
最近、クロスプラットフォーム開発への興味が湧いてきました。
そこで、以前から気になっていた 「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つあると思っています。
-
とにかく軽い!
- Electron はブラウザ(Chromium)を丸ごと抱え込むためサイズが大きくなりがちですが、Tauri は OS 標準の WebView を借りて動くので、アプリのサイズが劇的に小さくなります
-
Web の知識がそのまま使える
- 普段 Web 開発をしている人なら、学習コストを抑えてネイティブアプリ開発に着手できます
-
2.0 からモバイル対応が本格化
- デスクトップだけでなく、iOS や Android アプリも視野に入れて開発できるようになりました
Electron や Flutter との違いは?
クロスプラットフォームといえば、ElectronやFlutter、React Nativeといった候補があるかと思います。
「結局どれを使えばいいの?」と迷うところですが、私の理解ではこんなイメージです。
- Electron: 実績豊富で何でもできるけど、配布サイズや実行時の使用メモリ量が多くなりがち
- Flutter: スマホアプリに強く UI も綺麗だけど、Dart 言語の習得が必要
- React Native: モバイル中心にネイティブUIを扱えるが、デスクトップ対応は選択肢が限られる
- Tauri 2.0: 「Web 技術を活かしたい」かつ「軽快なアプリを作りたい」 人にピッタリ
早速プロジェクトを作ってみる!
今回は Windows 環境で試してみました。
事前に公式の前提条件に沿って、Node.jsやRust、Microsoft 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のプロジェクトはBash・PowerShell・npm・Fish・Yarn・pnpm・deno・bun・Cargoでプロジェクトを作成することができるようです。
今回はnpmでプロジェクトを作成しました。
npm create tauri-app@latest
すると、対話形式でいくつか質問されます。
英語で聞かれますが、基本的には好きなものを選ぶだけなので怖くありません。今回は社内の技術スタックに合わせて Vue + TypeScript の構成にしてみました。
実際のやり取りはこんな感じです。
-
追加パッケージのインストール確認
-
Need to install the following packages: create-tauri-app@...と表示されるので、そのままEnter(yのままで OK)
-
-
Project name(プロジェクト名)
-
tauri-app(デフォルトのまま Enter!)
-
-
Identifier(識別子)
-
com.my_name.tauri-app(これもデフォルトで Enter!) - 自分のドメイン風の文字列に変えても構いません。
-
-
Choose which language to use for your frontend(フロントエンドの言語)
-
TypeScript / JavaScriptを選択してEnter! - 選択肢の変更は上下キーで行えます
-
-
Choose your package manager(パッケージマネージャ)
- いつも使っている
npmを選択してEnter!
- いつも使っている
-
Choose your UI template(UIテンプレート)
- 社内の技術スタックに合わせて
Vueを選択(React や Svelte なども選べます)
- 社内の技術スタックに合わせて
-
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
少し待つと・・・・・・・
立ち上がりました!

おお、普通のブラウザではなく、独立したウィンドウとしてアプリが表示されています!
Tauri と Vite と Vue のロゴが並んでいるのが誇らしいですね。
無事、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/core の invoke)を使って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 のコマンド」についてもう少し踏み込んでみたいと思います。
出典・参考リンク
