Skip to main content
ブログに戻る
ブログ

Electron ではなく Tauri で MadoHub を作った理由

デスクトップ開発ツールとして Tauri v2 を選んだ技術的理由。パフォーマンス、バイナリサイズ、そしてシステム統合における Rust の利点を解説します。

MadoHub の開発を始めたとき、要件は明確でした。PTY セッションを管理し、ファイルシステムを読み、システムプロセスと深く連携できる、Web ベース UI のデスクトップアプリケーションです。真剣に検討したのは Electron と Tauri の 2 つでした。

私たちは Tauri を選びました。その理由と、そこから学んだことを紹介します。

バイナリサイズの話

Tauri の最もよく知られた利点はバイナリサイズです。空の Electron アプリは、フル Chromium ブラウザを同梱するため約 150MB になります。Tauri アプリは、システムのネイティブ webview(macOS では WebKit、Windows では WebView2、Linux では WebKitGTK)を使うため、5MB 未満から始まります。

開発者向けツールでは、バイナリサイズは思う以上に重要です。開発者はインストールするものに厳しいからです。「生産性ツール」として 200MB のダウンロードは警戒されます。10MB のダウンロードは、「軽量で目的がはっきりしている」と伝わります。

ただし、バイナリサイズは私たちの判断で最も重要な要素ではありませんでした。

Rust バックエンド

Tauri を選んだ本当の理由は Rust バックエンドです。

MadoHub は、PTY セッションの管理、tmux ペインの監視、JSONL ファイルの解析、ルーティングの API 呼び出し、ファイルシステム操作を、すべて並行で扱います。これはシステムレベルの操作であり、次のような利点があります。

ガベージコレクションなしのメモリ安全性: PTY 管理では、プロセスのライフサイクル、ファイルディスクリプタ、シグナルを扱います。Node.js(Electron のバックエンド)では、プロセス管理のバグがファイルディスクリプタを漏らしたり、ゾンビプロセスを残したりします。Rust の所有権モデルは、こうしたバグをコンパイル時に捕まえます。

真の並行性: MadoHub は複数の端末プロセスを同時に監視し、バックグラウンドスレッドで tmux ペインをポーリングし、ルーティング用の API を並行で叩きます。Rust の async ランタイム(tokio)は、これを低オーバーヘッドで扱えます。Node.js でも async I/O はできますが、巨大な JSONL を解析するような CPU 負荷の高い処理はイベントループを止めます。

構造化されたエラー処理: システム操作の失敗は、だいたい予測可能です。ファイルがない、プロセスが終了した、API がタイムアウトした。Rust の Result 型は、あらゆる失敗経路を必ず扱わせます。私たちの routing コードでは、これは「session file not found, falling back to CWD resolution」のようなきれいな処理と、undefined エラーで routing パイプラインが落ちることの差になります。

私たちの Rust ワークスペース

MadoHub のバックエンドは、7 つのフォーカスされた crate に分かれています。

Crate責務
madohub-ptyPTY セッション管理、tmux 連携
madohub-paneチーム監視のための tmux ペインポーリング
madohub-agentエージェントルーティング、JSONL 解析、API 呼び出し
madohub-gitGit 操作(status、commit、push)
madohub-team~/.claude/teams/ からのチーム検出
madohub-persistence~/.madohub/ へのキャンバス状態シリアライズ
madohub-core共有イベントエミッタトレイト

このモジュール構成のおかげで、各 crate を独立してテストでき、変更のない crate を再コンパイルしないので、コンパイル時間も現実的に保てます。

フロントエンドの話

Tauri のフロントエンドは、標準的な Web アプリを描画する webview です。私たちは React 19 + TypeScript + Tailwind CSS + Zustand を状態管理に使っています。Web アプリで使うのと同じスタックです。

フロントエンドとバックエンドの通信は、Tauri の command システム、つまり型付き IPC を通じて行われます。フロントエンドが Tauri command を呼び、Rust バックエンドがそれを実行し、結果が返ってきます。ストリーミングデータ(端末出力、ルーティングイベント)には、Tauri のイベントシステムを使います。

見落とされがちな利点の 1 つは、webview がシステムのネイティブ描画エンジンを使うことです。そのため、プラットフォーム固有のテキスト描画、スクロールの物理感、アクセシビリティ機能を継承します。MadoHub の文字がネイティブに見えるのは、実際にネイティブ描画だからです。

捨てたもの

Tauri にもトレードオフはあります。

クロスプラットフォームの webview 差異: WebKit(macOS)と WebView2(Windows)は、端のケースで描画が異なります。CSS の backdrop-filter の挙動が違ったり、スクロールの挙動が異なったり、より新しい Web API の到着時期が違ったりします。私たちは主にアニメーションやブラー効果で、いくつか経験しました。

エコシステムの小ささ: Electron には、10 年分のプラグイン、デバッグツール、コミュニティ知識があります。Tauri のエコシステムは急成長中ですが、まだ若いです。Electron なら npm パッケージで済んだものを、自分たちで作らなければならないことがありました。

Rust の学習曲線: フロントエンドチームは主に TypeScript 開発者です。バックエンドで Rust を書くには習熟時間が必要でした。システムレベルのコードにはその価値がありますが、初期投資は確かにあります。

実運用での性能

MadoHub のようなツールでは、5 つのターミナルタイルが開き、それぞれが PTY 出力を流しながら、routing システムが完了を監視し、tmux ペインをポーリングしているという状況があり得ます。ここでは性能は理論ではありません。キャンバスのフレーム落ち、重い端末描画、遅い routing トリガーは、そのまま使い勝手に響きます。

ベンチマークでは、8 つのアクティブなターミナルタイルを持つ MadoHub は約 120MB の RAM を使います。等価な Electron アプリは、ターミナルを 1 つも開く前から Chromium のオーバーヘッドだけで 300MB 以上になります。

通常動作(ターミナル稼働、routing 待機中)の CPU 使用率は 5% 未満です。アクティブルーティング中(API 呼び出し + JSONL 解析 + コンテンツ配信)は一時的に 15〜20% に跳ね上がり、その後ベースラインに戻ります。

もう一度 Tauri を選ぶか?

この種のアプリケーションなら、間違いなく Yes です。システムレベルの Rust バックエンドと Web ベースのフロントエンドの組み合わせは、深い OS 統合が必要な開発者ツールに自然に合っています。

もっと単純なアプリ - 基本的なファイル I/O 以外にシステム連携がないもの - なら、選択はもっと微妙です。Electron の成熟度とエコシステムの大きさは、多くの用途で現実的な選択になります。

しかし MadoHub のように、バックエンドが並行 PTY セッションを扱い、システムプロセスを監視し、高スループットで構造化データを解析するなら、Rust は単なる性能最適化ではありません。自信を持って出荷するための正しさの保証です。