Electron代替フレームワーク比較: Tauri・Wails・Neutralinojsを選ぶ基準
Electronからの移行または新規デスクトップアプリのために、Tauri、Wails、Neutralinojsのランタイム、権限、WebView、運用コストを比較します。
まず、捨てたいコストに名前を付ける
Electron代替を探す理由を「アプリを軽くしたい」だけにすると、移行後に別の重さを見つけます。インストーラー、メモリ、ビルド時間、Chromium更新、OS別UI差、Node.jsの権限、IPCのレビュー、既存プラグイン、チームの言語能力は別々の費用です。先に「どの費用をどの利用者のために下げたいか」を記述します。
たとえば、配布物を小さくしたいのか、Chromiumを同梱して更新する運用を減らしたいのか、rendererとOS APIの境界を厳しくしたいのか、既存Goサービスをローカル機能へ持ち込みたいのか。目的が異なれば、Tauri、Wails、Neutralinojsの適切な評価軸も変わります。
| 現在の痛み | 最初に測るもの | 見落としやすい費用 |
|---|---|---|
| 配布物が大きい | OS別インストーラー、ダウンロード、初回起動 | WebView前提、サポート対象OS |
| メモリが気になる | 中核行動中のCPU・メモリ・起動後の安定性 | 画像、一覧、IPC、バックグラウンド処理 |
| IPCが広い | rendererが到達可能な能力一覧 | 移行後の新しいブリッジ設計 |
| ビルドが遅い | CI時間、署名、失敗率 | SDK・Rust・Goツールチェーン |
| UIを統一したい | OS別の実機QA結果 | システムWebViewの差 |
三つのフレームワークは同じWebViewアプリではない
三つともWeb技術のUIをデスクトップへ持ち込みますが、ネイティブコードとの接点と安全に保つ方法が異なります。
| 観点 | Tauri | Wails | Neutralinojs |
|---|---|---|---|
| ネイティブ側 | Rust commandとプラグイン | Goのメソッド・サービス | JavaScript APIと拡張 |
| 画面 | システムWebView | システムWebView | システムWebView |
| 典型的な強み | capability・permission・scopeによる明示的境界 | Goで書いた既存ドメイン処理との接続 | 小さい単機能ツールの単純な構成 |
| 主な確認点 | OS別WebView、Rust、権限ファイル | Go境界、バインディング、OS別描画 | 必要API、更新、製品規模の上限 |
この表は優劣ではなく、どの境界をチームが保守できるかを示します。どれでも、画面に任意のローカル権限を渡さず、端末機能を小さいAPIで囲う設計は必要です。
Tauri: 権限モデルまで製品コードとして扱いたいとき
TauriはWebフロントエンドとRustコアを結び、OSのWebViewを使います。価値は単純な軽量化だけでなく、windowごとのcapability、permission、scopeにより、画面が何へ到達できるかを設定とコードで明示できることです。
#[tauri::command]
fn export_note(body: String) -> Result<(), String> {
if body.len() > 1_000_000 { return Err("Note is too large".into()); }
// 保存先・権限・入力検証はここでさらに限定する
Ok(())
}
{
"identifier": "editor",
"windows": ["main"],
"permissions": ["core:default", "dialog:allow-save"]
}
Rustを新たに導入する費用、Windows・macOS・LinuxのWebView差、プラグインのpermission識別子を版ごとに確認する運用は必要です。Tauriを選ぶなら「バンドルが小さいから」ではなく、ローカル能力を狭く監査したいという目的を満たせるかで判断します。
Wails: Goのサービスモデルをデスクトップへ持ち込みたいとき
WailsはGoバックエンドとWebフロントエンドを結びます。既にGoでドメインロジック、同期、ローカルDB、CLI、サービス層を持つチームなら、言語境界を増やさずにデスクトップ化できることがあります。フロントエンドから呼ぶGoの公開メソッドは、HTTP APIと同様に入力・出力・エラーを契約として扱います。
// app.go
type App struct{}
type ExportInput struct { Name string; Body string }
func (a *App) ExportMarkdown(input ExportInput) error {
if len(input.Body) > 1_000_000 { return errors.New("export is too large") }
if !strings.HasSuffix(input.Name, ".md") { return errors.New("only .md is allowed") }
return nil
}
Goのメソッドを広く公開すると、Electronで任意IPCを公開するのと同じ問題を別名で作ります。UIの用途ごとに小さなサービスを設け、ファイルパス、サイズ、状態をGo側で検証します。Go採用の利点が既存資産ではなく単なる「Rustを避けたい」だけなら、長期の保守責任まで比較してください。
Neutralinojs: 小さく単純なツールの境界を明確にしたいとき
Neutralinojsは小さなデスクトップユーティリティを考える際に候補になります。メニューバー補助、ローカルデータの表示、単発の変換ツールのように、端末機能が限られ、長期的に大規模な統合を必要としない場合に相性を評価できます。
小さいランタイムは「機能が自動的に安全」とは意味しません。どのnative APIをUIへ渡すか、ユーザー入力をどこで検証するか、更新、署名、クラッシュ報告をどう運用するかは製品で決める必要があります。まず必要なOS APIをリスト化し、PoCでOS別のファイル、ダイアログ、通知、描画を通します。
// 例: UIから任意のシェル操作を許さず、用途を限定した関数にする
export async function exportText(name: string, body: string) {
if (!name.endsWith('.txt')) throw new Error('Text files only');
if (body.length > 1_000_000) throw new Error('File too large');
// 実際のnative APIは導入したバージョンの文書に合わせる
}
システムWebViewはコストを消すのでなく、場所を変える
Chromiumを同梱しない選択は配布物を小さくできることがありますが、描画エンジンの更新をOSや環境に委ねることでもあります。フォント、入力、ドラッグ&ドロップ、アクセシビリティ、CSS機能、動画、エディタ、認証画面を、対象OSの実機で試します。ChromeのスクリーンショットだけでWebView QAを済ませません。
| 検証場面 | 記録すること |
|---|---|
| 初回起動 | OS、WebView版、起動までの時間、失敗時メッセージ |
| 編集・IME | 日本語入力、貼付け、ショートカット、フォーカス移動 |
| ファイル | ダイアログ取消、権限なし、外部ボリューム、長いパス |
| 認証 | リダイレクト、外部ブラウザ、セッション復帰 |
| 更新 | 署名、失敗時の復旧、既存データの移行 |
移行はrendererから始めない
Electronのrendererを先にコピーすると、古いpreload API、IPC名、Node前提をそのまま新しいフレームワークへ持ち込む危険があります。最初にやるべきは、現在のアプリが持つ能力を列挙し、画面、preload、main、外部サーバーのどこにあるかを可視化することです。
現在の能力
ファイルを選ぶ ── dialog
下書きを保存 ── preload → IPC → main → fs
更新を確認 ──── main → 更新サービス
分析を送る ──── renderer → HTTPS API
次に、各能力の入力、戻り値、権限、失敗時UIを一つずつ書きます。新フレームワークではそれをRust command、Goメソッド、または限定native APIへ写します。UIコンポーネントの移植は最後に近い仕事です。UIは古い能力を呼ばないアダプターを通すようにしておけば、移行中もブラウザ版とテスト版を保てます。
export interface FileExporter {
chooseDestination(): Promise<string | null>;
writeMarkdown(path: string, body: string): Promise<void>;
}
4週間の意思決定PoCに必要な最小範囲
PoCの目的はフレームワークの見た目を比べることではなく、戻りにくい前提を検証することです。
- 1週目: 対象OS、署名、起動、WebView上の中核画面を確認する。
- 2週目: 最も危険なローカル機能(ファイル、資格情報、DBなど)を最小権限で通す。
- 3週目: 認証、オフライン、データ移行、エラー表示を実機で通す。
- 4週目: CI、パッケージ、更新、アンインストール/再インストール、運用手順を記録する。
成果は「成功したデモ」ではなく、OS、SDK、署名、権限、失敗ケース、未解決コストの一覧です。
選択のための短い決定ツリー
既存Electronで解決できない具体的なコストがあるか?
└─ ない → Electronの保守・セキュリティ境界をまず改善
└─ ある → 既存Go資産が中心か?
└─ はい → WailsのPoC
└─ いいえ → 権限を宣言的に狭め、Rust境界を置きたいか?
└─ はい → TauriのPoC
└─ いいえ → 機能が小さい単機能ツールか?
└─ はい → Neutralinojsを含めてPoC
└─ いいえ → 現行Electronまたは要件の再整理
まとめ: 軽量化より、運用できる境界を選ぶ
良い移行はベンチマークの一行で決まりません。ユーザーが本当に行う仕事、端末のどの能力へ届くか、誰が更新・署名・障害対応を担うかを対象OSで検証し、運用できる境界を選びます。Tauri、Wails、Neutralinojsはいずれも有力な選択肢ですが、既存Electronを改善する方が合理的な場合もあります。選択の品質は、移行後のランタイム名ではなく、権限・配布・失敗経路を説明できることに現れます。