TauriとReactでElectronの「メモリ消費の悪夢」を打破する:究極の超軽量デスクトップアプリ開発

Development tutorial - IT technology blog
Development tutorial - IT technology blog

深夜2時の衝撃:たった一つの「Hello World」がメモリを飲み込む

深夜2時ちょうど、私の電話が激しく震えました。クライアントからのメッセージで、納品したばかりの社内ダッシュボードのせいで会計担当者のPCが完全にフリーズしたという苦情でした。タスクマネージャーを開いて、私は愕然としました。グラフとデータテーブルを表示するだけのシンプルなアプリケーションが、なんと1.5GBものRAMを消費していたのです。犯人は他でもない、Electronでした。

この問題は、決して私だけのものではありません。ElectronはHTML/CSS/JSでデスクトップアプリを作れるため非常に便利ですが、その代償として、各ビルドにChromiumエンジンとNode.jsランタイムを丸ごと抱え込むことになります。空のアプリを起動しただけで数百MBのRAMを占有するのは日常茶飯事ですし、インストールファイルが100MB近くになることも珍しくありません。

なぜElectronはこれほど重いのか?

Electronの仕組みを見れば、問題は明らかです。Electronアプリを実行するたびに、コンピュータはChromiumのインスタンスを生成します。Slack、Discord、VS Code、Spotifyなど、10個の異なるアプリを開いていると想像してみてください。その時、システムは裏で10個のChromeブラウザを動かしているのと同じなのです。これはとてつもないリソースの無駄遣いです。

さらに、Node.jsのソースコード全体と巨大なnode_modulesをパッケージングするため、アプリのサイズは急速に膨れ上がります。軽量化とセキュリティが求められるプロジェクトにおいて、Electronはアップデートでは解決できない致命的な弱点を露呈し始めています。

速度と利便性のバランスを求めて

この課題に直面し、私は主に3つの方向性を検討しました:

  • Native (C++/C#): パフォーマンスは最高でアプリも超軽量ですが、開発時間がかかりすぎます。CSSを使った複雑なUIデザインも贅沢品になってしまいます。
  • Python (PyQt/PySide): C++よりは書きやすいですが、パッケージング(packaging)が地獄です。エンドユーザーの環境で依存関係のエラーが頻発します。
  • Tauri: 今まさに旋風を巻き起こしている「新星」です。Rustをシステム処理の核(バックエンド)として使い、UIにはReact、Vue、SvelteなどのあらゆるWebフレームワークを使用できます。

Tauri — Rustのように強力で、「羽のように軽い」ソリューション

いくつかの実機テストを経て、私はTauriを選びました。最大の違いは、TauriがChromiumを同梱しないことです。代わりに、OS標準のWebView(WindowsならWebView2、macOS/LinuxならWebKit)を利用します。その結果は驚くべきものでした。インストールファイルは80MBからわずか4MBに激減し、RAM使用量も同じ機能で1.5GBから100MB以下に抑えられました。

ステップ 1:環境構築(ここを飛ばさないで!)

TauriはRustベースで動作するため、まず Rustコンパイラをインストールする必要があります。心配しないでください。アプリを作るためにRustの専門家になる必要はありません。

# rustupを使用してRustをインストール(Windows/Mac/Linux)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Reactを動かすためにNode.jsのチェックも忘れずに:

node -v
npm -v

ステップ 2:Tauri + Reactプロジェクトの初期化

時間を節約するために、手動設定ではなくクイックコマンドを使用します:

npm create tauri-app@latest

ターミナルにいくつかの選択肢が表示されます。TypeScript / JavaScriptを選択し、次にビルド速度が最も速いReactとViteの組み合わせを選択してください。

ステップ 3:ディレクトリ構造を解読する

初期化後、src-tauriというフォルダが作成されます。ここにはRustのコードが格納され、重い処理やシステムへの深い干渉を担当するバックエンドとして機能します。一方、srcフォルダは通常通りReactのコードを書く場所です。

UIの実装中、APIからの複雑なJSON文字列を処理する必要がある場合、私はよくtoolcraft.appのツールを利用します。例えば、JSON Formatterを使えば、VS Codeに余計な拡張機能を入れずに素早くデータをテストできます。

ステップ 4:「Bridge(架け橋)」機能の実装

Tauriの最大の魅力は、JavaScriptからRustの関数を呼び出す仕組み(Commands)です。PC内のファイルを読み取るような処理は、安全面とパフォーマンスを考慮してNode.jsではなくRustに任せましょう。

src-tauri/src/main.rsファイルにて:

#[tauri::command]
fn greet(name: &str) -> String {
    // 日本語のメッセージを返す
    format!("こんにちは{}さん、このアプリはわずか4MBで、2秒足らずで起動します!", name)
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("Tauriアプリの実行中にエラーが発生しました");
}

React側(App.tsx)での呼び出しは非常にシンプルです:

import { invoke } from '@tauri-apps/api/tauri';

const handleGreet = async () => {
  // Rustのgreet関数を呼び出す
  const message = await invoke('greet', { name: 'Thanh' });
  console.log(message);
};

ステップ 5:ビルドして成果を享受する

すべてが整ったら、ビルドコマンドを実行して完成したインストールファイルを作成します:

npm run tauri build

src-tauri/target/release/bundleフォルダを確認してください。信じられないほど軽量な.msi.dmgファイルができているはずです。その時の感覚は、まさに千斤の重荷を下ろしたような気分です。

結論:いつTauriを選ぶべきか?

Tauriは強力ですが、すべてのケースにおける万能薬ではありません。アプリがChromium固有の機能に深く依存している場合や、Rustに一切触れずにバックエンドを100% Node.jsで完結させたい場合は、依然としてElectronが安全な選択肢となります。

それでも、現在のパフォーマンス最適化のトレンドにおいて、Tauriが強力なライバルであることは間違いありません。Reactによる美しさと、Rustによる速さと安全さを兼ね備えたアプリを構築できます。もし新しいデスクトップアプリのプロジェクトを計画しているなら、ぜひ一度Tauriを試してみてください。きっと二度とElectronには戻りたくなくなるはずです。

Share: