はじめに:なぜ今 Tauri なのか
Electron のようなフレームワークは便利ですが、「アプリサイズが大きい」「メモリを食う」といった悩みを抱えがちです。
Tauri は、OS がもともと持っている WebView を利用し、Rust をバックエンドに採用することで、「小さくて速くて安全」なデスクトップアプリを目指して作られました。
このガイドでは、Tauri 初心者を想定し、「専門用語の意味 → 実際のコード → どう使うか」という流れで、丁寧にステップアップしていきます。
第1章:Tauri とは?アーキテクチャをイメージしよう
Tauri は「クロスプラットフォームなアプリ開発ツールキット」で、Windows・macOS・Linux などで動くデスクトップアプリを 1 つのコードベースから作成できます。
構造としては、画面を描く「フロントエンド部分(Web)」と、OS 機能に触れる「バックエンド部分(Rust)」がプロセスを分けて動作し、専用の IPC(プロセス間通信)を使って安全にやり取りします。
Electron のように独自のブラウザ(Chromium)を同梱せず、OS 標準の WebView を使うため、インストーラサイズやメモリ使用量を小さく抑えられるのが特徴です。
第2章:Tauri とよく出る用語の意味
Tauri の公式ドキュメントや記事を読むと、「WebView」「IPC」「コマンド」「プラグイン」などの用語が頻出するので、最初に押さえておきましょう。
WebView は「OS が提供する小さなブラウザ」で、Tauri アプリのウィンドウ内部で HTML/JS を表示している仕組みです。
IPC(Inter-Process Communication)は「プロセス間通信」のことで、フロント(JavaScript)からバックエンド(Rust 関数)を呼び出す橋渡しをする Tauri 独自の仕組みが用意されています。
Tauri の「コマンド」は、Rust 側で #[tauri::command] を付けた関数のことで、JavaScript から invoke() で呼び出せるようになるエンドポイントだと考えると理解しやすいです。
第3章:開発環境の準備とプロジェクト作成
Tauri を始めるには、Rust のツールチェーン(rustup / cargo)と、Node.js とパッケージマネージャ(npm / pnpm / yarn など)の両方が必要です。
その上で、Tauri 公式が提供している create-tauri-app を使うと、テンプレート選択付きでテキパキとプロジェクトのひな型を作成できます。
必要ツール(代表例)
- Rust ツールチェーン:
https://www.rust-lang.org/からインストール - Node.js(推奨 LTS)
- どれか 1 つのパッケージマネージャ(npm / pnpm / yarn)
プロジェクト作成コマンド例
# npm の場合
npm create tauri-app@latest my-tauri-app
# pnpm の場合
pnpm create tauri-app@latest my-tauri-app
# yarn の場合
yarn create tauri-app my-tauri-app
コマンドを実行すると、アプリ名やバンドル ID、フロントエンドのフレームワーク(Vanilla / React / Vue / Svelte など)を対話形式で聞かれます。
最後まで答えると、my-tauri-app ディレクトリにフロントエンド+src-tauri ディレクトリが作られ、すぐ動かせる状態になります。
第4章:Tauri プロジェクトのディレクトリ構成を理解する
生成されたプロジェクトを開くと、少なくとも「フロントエンド側のフォルダ」と「src-tauri フォルダ」の 2 つがあるのが分かります。
フロントエンド側(例:src/ や app/ ディレクトリなど)は、通常の Web アプリと同じ感覚で HTML/CSS/JS や React/Vue のコードを書く場所です。
src-tauri ディレクトリには、Rust のソースコード・設定ファイル(tauri.conf.json など)が入り、ウィンドウの設定やメニュー、アイコン、ビルド設定などもここで管理されます。
構成イメージ(シンプル化):
my-tauri-app/
package.json
src/ # フロントエンド (例: Vite + React)
public/
src-tauri/
src/
main.rs # Rust のエントリポイント
tauri.conf.json
Cargo.toml # Rust の依存関係
この構造を頭に入れておくと、「Web 部分を触るのか」「ネイティブ機能を追加するのか」でどのフォルダを編集すればよいか迷わなくなります。
第5章:最初の「Hello Tauri」アプリを起動する
雛形ができたら、まずはローカルで開発用サーバを立ち上げてみましょう。
Tauri では、フロントエンドの開発サーバ(例:Vite)が起動しつつ、Rust 側で Tauri アプリがコンパイルされ、実際のデスクトップウィンドウとして表示されます。
起動コマンド(例:npm)
cd my-tauri-app
npm install # まだなら依存パッケージをインストール
npm run tauri dev # Tauri 開発モードで起動
成功すると、コンソールにビルドログが流れ、しばらくしてから OS ネイティブのウィンドウが 1 つ立ち上がり、その中でフロントエンドの画面が表示されます。
この時点ではまだ機能はシンプルですが、「ブラウザではなくアプリとして動いている」ことが体感できるはずです。
第6章:Rust 側にコマンドを定義してみる
ここからが Tauri らしい部分です。Rust 側で「コマンド」と呼ばれる関数を定義し、それを JavaScript から呼び出せるようにします。
コマンドは「Rust の普通の関数に、#[tauri::command] という属性を付けたもの」で、Tauri が IPC を通じてフロントエンドからの呼び出しを仲介してくれます。
src-tauri/src/main.rs の最小例:
// src-tauri/src/main.rs
// 挨拶用コマンド
#[tauri::command]
fn greet(name: &str) -> String {
format!("こんにちは、{} さん!Rust からのメッセージです。
}
fn main() {
tauri::Builder::default()
// ここで、使用するコマンド関数を登録する
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
ポイントは invoke_handler(tauri::generate_handler![greet]) の部分で、ここに列挙した greet 関数だけがフロントエンドから呼べるようになります。
この仕組みにより、「使うネイティブ API を限定し、不要なものを閉じる」ことでセキュリティを高めている点も Tauri の特徴です。
第7章:JavaScript から Rust コマンドを呼ぶ
Rust 側で greet コマンドを定義したので、今度はフロントエンドからそれを呼び出してみましょう。
Tauri は JavaScript 用に @tauri-apps/api パッケージを提供しており、その中の invoke 関数を使って Rust コマンドを簡単に呼び出せます。
例:Vite + Vanilla JS のシンプルなフロントエンド
<!-- index.html の一部 (イメージ) -->
<body>
<h1>Tauri サンプル</h1>
<input id="name-input" placeholder="名前を入力" />
<button id="greet-button">挨拶する</button>
<p id="result"></p>
<script type="module">
import { invoke } from '@tauri-apps/api/tauri';
const input = document.querySelector('#name-input');
const button = document.querySelector('#greet-button');
const result = document.querySelector('#result');
button.addEventListener('click', async () => {
const name = input.value || 'World';
// Rust 側の greet コマンドを呼び出す
const message = await invoke('greet', { name });
result.textContent = String(message);
});
</script>
</body>
ここでのポイントは、invoke('greet', { name }) の第一引数が Rust 側の関数名(スネークケースのまま)で、第二引数のオブジェクトが引数の名前と対応していることです。
このしくみを理解すれば、フロントエンドから自由に Rust の処理(ファイル操作や OS 情報取得など)を呼び出せるようになります。
第8章:設定ファイル tauri.conf.json を読んでみる
src-tauri/tauri.conf.json は、アプリ名やウィンドウのサイズ、起動時 URL など、Tauri 全体の挙動をコントロールする大事な設定ファイルです。
このファイルを編集することで、「起動時に最大化する」「タイトルバーをカスタムにする」「ビルド時のアイコンを指定する」といった調整ができます。
シンプルな例(抜粋イメージ):
{
"package": {
"productName": "My Tauri App",
"version": "0.1.0"
},
"tauri": {
"windows": [
{
"title": "My Tauri App",
"width": 800,
"height": 600,
"resizable": true
}
],
"security": {
"csp": null
}
}
}
windows セクションはウィンドウごとの設定、security では Content Security Policy などのセキュリティ設定が行えます。
最初はデフォルトのままでも動きますが、UI/UX を詰めたくなったときに、このファイルを読むことで「Tauri が何をしているか」がよく見えてきます。
第9章:ファイルを読み書きする簡単なツールを作る
デスクトップアプリらしく、ローカルファイルを読み書きするサンプルを作ってみましょう。
ここでは「メモ帳風アプリ」として、テキストファイルを保存・読み込みする機能を Rust コマンドに実装します。
Rust 側の例:
// src-tauri/src/main.rs
use std::fs;
use std::path::PathBuf;
#[tauri::command]
fn save_text(path: String, content: String) -> Result<(), String> {
fs::write(path, content).map_err(|e| e.to_string())
}
#[tauri::command]
fn load_text(path: String) -> Result<String, String> {
fs::read_to_string(path).map_err(|e| e.to_string())
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![save_text, load_text])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
JavaScript からの呼び出し例:
import { invoke } from '@tauri-apps/api/tauri';
async function save() {
const content = document.querySelector('#editor').value;
await invoke('save_text', { path: 'note.txt', content });
alert('保存しました');
}
async function load() {
const text = await invoke('load_text', { path: 'note.txt' });
document.querySelector('#editor').value = text;
}
これだけで、アプリのカレントディレクトリに note.txt を保存・読み込みできるようになりますが、実運用では「ファイルダイアログを開く」などを組み合わせてより自然な UX にできます。
第10章:ダイアログと通知でネイティブ感を出す
デスクトップアプリらしさを高めるには、ネイティブのダイアログや通知を利用すると効果的です。
Tauri には、JavaScript からそのまま呼べる @tauri-apps/api/dialog や @tauri-apps/api/notification といったモジュールが用意されています。
ファイル選択ダイアログの例:
import { open } from '@tauri-apps/api/dialog';
import { invoke } from '@tauri-apps/api/tauri';
async function openFile() {
const selected = await open({
multiple: false,
filters: [{ name: 'Text', extensions: ['txt'] }]
});
if (typeof selected === 'string') {
const text = await invoke('load_text', { path: selected });
document.querySelector('#editor').value = text;
}
}
通知の例:
import { isPermissionGranted, requestPermission, sendNotification } from '@tauri-apps/api/notification';
async function notify() {
let granted = await isPermissionGranted();
if (!granted) {
const permission = await requestPermission();
granted = permission === 'granted';
}
if (granted) {
sendNotification({
title: 'Tauri 通知',
body: 'ファイルの保存が完了しました。'
});
}
}
こうした API を組み合わせていくと、ブラウザではできない OS との連携が簡単に実現できます。
第11章:ウィンドウ制御とマルチウィンドウ
Tauri では、メインウィンドウだけでなく、設定画面やヘルプ画面などサブウィンドウを開くこともできます。
JavaScript から @tauri-apps/api/window を使うと、ウィンドウの最小化・最大化・新規作成などが簡単に行えます。
新しいウィンドウを開く例:
import { WebviewWindow } from '@tauri-apps/api/window';
function openSettingsWindow() {
const settings = new WebviewWindow('settings', {
url: 'settings.html',
title: '設定',
width: 400,
height: 300
});
settings.once('tauri://created', () => {
console.log('設定ウィンドウが作成されました');
});
}
ウィンドウの状態を制御する例:
import { appWindow } from '@tauri-apps/api/window';
async function toggleMaximize() {
const isMaximized = await appWindow.isMaximized();
if (isMaximized) {
await appWindow.unmaximize();
} else {
await appWindow.maximize();
}
}
これらを活用すれば、「メインは作業画面」「サブウィンドウでログや設定を表示」というような、デスクトップアプリらしいレイアウトが作れます。
第12章:セキュリティと権限を意識した設計
Tauri の思想の 1 つに「最小権限」があり、アプリ内で使うネイティブ API やコマンドは必要なものだけを明示的に有効化する設計になっています。
たとえば、tauri.conf.json で許可していないドメインへの外部リクエストを制限したり、コマンドを慎重に設計することで、不必要にローカルファイルやネットワークに触れないようにできます。
セキュリティ設定の一例(イメージ):
{
"tauri": {
"security": {
"csp": "default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com"
},
"allowlist": {
"fs": {
"readFile": true,
"writeFile": true
},
"dialog": {
"open": true
}
}
}
}
allowlist セクションで、ファイルシステムやダイアログ API のどの機能を許可するかを細かく制御できるため、必要最小限の権限でアプリを動かすことが可能です。
これにより、「Web 技術で作られたデスクトップアプリ」でありながらも、堅牢なセキュリティ基盤の上に成り立っている点が Tauri の大きな強みとなります。
第13章:アプリをビルドして配布用バイナリを作る
開発が進んだら、ユーザーに配布するためのインストーラや実行ファイルをビルドします。
Tauri は各 OS 向けのネイティブバイナリ(.exe / .app / .deb など)を生成でき、Electron よりもかなり小さいサイズに収まるケースが多いです。
ビルドコマンド例:
# リリースビルド
npm run tauri build
これにより、src-tauri/target/release/ 以下に OS 向けのバイナリが生成され、さらにインストーラ形式のファイル(Windows installer など)も作られます。
GitHub Releases などにアップロードして配布したり、社内利用であれば社内ストレージに置いてユーザーに配布する運用が一般的です。
第14章:プラグインとエコシステムを活用する
Tauri には、公式・コミュニティ製のプラグインが多数存在し、OAuth 認証やストレージ、アップデート機能などを簡単に追加できます。
プラグインは Rust 側の依存として追加し、必要に応じて設定ファイルにも登録する形で組み込みます。
例:プラグインを Cargo.toml に追加(イメージ)
[dependencies]
tauri = { version = "2.0", features = ["shell-all"] }
tauri-plugin-store = "2.0"
Rust 側でプラグインを登録するコード例:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_store::Builder::default().build())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
プラグインを使うことで「設定の永続化」「自動アップデート」「OS のシェルコマンド実行」など、ゼロから自分でラッパーを書くよりも安全で統一された方法で実現できるようになります。
第15章:実践的なアプリアイデアと次の一歩
ここまでで、Tauri の基本的な構成、Rust コマンド、JavaScript からの呼び出し、ファイル操作、ダイアログ、セキュリティ、ビルドまで一通り体験できました。
次のステップとしては、実際に「自分が毎日使いたくなる小さなツール」を 1 つ決め、Tauri で作ってみるのがおすすめです。
たとえば:
- Markdown メモとプレビューを一体化したメモアプリ
- スクリーンショットを整理し、タグ付けするツール
- AI API(例:OpenAI やローカル LLM)と連携したプロンプト管理アプリ
といったアプリは、Web 技術と Rust の両方を活かしやすく、Tauri のメリットを強く感じられます。
Tauri 公式の日本語ドキュメントや GitHub のサンプルも充実してきているので、興味のある機能があれば、少しずつコードを読みながら、自分のアプリに取り入れていくと学びが深まります。
この 15 章を通じて、「Tauri とは何か」「どういう思想で設計されているのか」「どう使えばよいのか」が少しでもクリアになっていれば、次は小さなプロトタイプを 1 つ作ってみてください。
小さくて速いデスクトップアプリを、自分の好きなフロントエンド技術と Rust の力で育てていく体験は、とても楽しく、スキルアップにも直結します。