
ノバセル株式会社 MKPLA開発部 のTamtamです。
この記事はノバセル テクノ場 出張版2025 Advent Calendar 2025の14日目になります。
はじめに
ソフトウェア開発において、コーディングやコードレビューの領域ではAI活用が進んでいますが、「仕様を決める会議」や「設計を議論するミーティング」といったプランニング段階では、まだ十分に活用されていないと感じていました。そこで、会議中の会話をリアルタイムで解析し、議論の支援を行うAIアシスタントを個人開発で作ることにしました。音声をその場で文字起こしし、会話の文脈から見落としている論点やリスクをAIが能動的にサジェストするアプリです。
デスクトップアプリを選んだのは、ZoomやMeetといった会議ツールと併用しながらサジェストを常に視界に入れておきたかったからです。ElectronならBrowserWindowのalwaysOnTopオプションでウィンドウを最前面に固定できますが、Webアプリにはこの手段がありません。また、マイク入力とシステム音声を同時に扱う場面でも、ブラウザでは毎回許可ダイアログが必要で画面共有と一緒でないとシステム音声が取れませんが、ElectronのdesktopCapturer APIなら音声ソースを個別に指定できます。


普段はWebアプリケーション開発がメインでデスクトップアプリには馴染みがなかったのですが、electron-shadcn というテンプレートのおかげでプロトタイプ段階まではスムーズに開発を進めることができました。React + shadcn-ui という慣れ親しんだ技術スタックをそのまま使いながら、ネイティブ機能を組み込める。型安全なIPC通信が設定済みで、Electron Forgeによってビルドやパッケージングも統合されている——これは共有する価値があると感じました。
本記事では、デスクトップアプリ開発に馴染みがないWeb開発者の方に向けて、Electronの仕組みから実践的な開発フローまでを解説します。
想定読者: Web開発経験があり、デスクトップアプリ開発は初めての方
本記事でカバーする範囲: 開発環境のセットアップからプロトタイプ作成まで。本番配布(コード署名、自動アップデート等)については概要のみ触れます。
1. なぜElectronでデスクトップアプリを作るのか
Browser APIの限界
Webアプリは多くのユースケースをカバーできますが、以下のような場面ではブラウザの制約が壁になります。
ファイルシステムへの直接アクセス
ブラウザのFile System Access APIは進化していますが、依然として制限があります。ユーザーの明示的な許可が毎回必要で、アプリを閉じるとアクセス権が失われます。Electronならバックグラウンドでのファイル監視や、任意のディレクトリへの読み書きが可能です。
その他のユースケース
- グローバルショートカットの登録(他のアプリがフォーカスされていても動作)
- システムトレイへの常駐
- オフライン動作の完全なサポート
- システム音声のキャプチャ(ただし制限あり、後述)
⚠️ システム音声キャプチャについて(macOS)
macOSでのシステム音声キャプチャは、Electronを使っても制限があります。Electron公式ドキュメントによると、navigator.mediaDevices.getUserMediaはmacOSでの音声キャプチャに対応していません。これはシステム音声にアクセスするアプリが署名済みカーネル拡張を必要とするという根本的な制限によるものです。
ただし、macOS 13.2以降ではScreenCaptureKit APIを通じてシステム音声キャプチャが改善されているという報告もあります。
システム音声キャプチャが主目的の場合は、実装前にmacOSのバージョンごとの制限を十分に調査してください。
代替技術との比較
デスクトップアプリを作る選択肢はElectronだけではありません。要件に応じて以下も検討してください。
| 技術 | 特徴 | バンドルサイズ | 向いているケース |
|---|---|---|---|
| Electron | Chromium + Node.jsをバンドル。Web技術がそのまま使える | 120〜200MB程度(最適化後80〜120MB) | 既存のReact/Vue資産を活かしたい、Chromiumの描画互換性が必要 |
| Tauri | Rustベース。OS標準のWebViewを利用 | 3〜10MB程度 | アプリサイズを抑えたい、セキュリティ重視 |
| Flutter Desktop | Dartで記述。独自レンダリングエンジン | 20〜40MB程度 | モバイル版も同時に開発したい |
| PWA | インストール不要、Service Workerでオフライン対応 | N/A | ネイティブ機能が不要なら十分なケースも多い |
Tauriについての補足
Tauri 2.0は2024年10月2日に安定版としてリリースされ、モバイル対応(iOS/Android)も追加されました。よくある誤解として「Tauriを使うにはRustを書く必要がある」と言われますが、フロントエンドはWeb技術(React, Vue等)をそのまま使えます。Rustが必要になるのは、OSのネイティブAPIを直接呼び出すカスタムコマンドを実装する場合のみです。
ただし、TauriはOS標準のWebViewを使うため、プラットフォーム間でレンダリングの差異が生じる可能性も(Windows: WebView2/Chromium、macOS: WKWebView/Safari、Linux: WebKitGTK)。Electronはすべてのプラットフォームで同じChromiumを使うため、この問題がありません。
本記事ではElectronを選択していますが、これは筆者がReact + shadcn-uiに慣れており、その資産をそのまま活かしたかったためです。
2. Electronの仕組み
2.1 Electronとは何か
Electronは一言で言うと 「Chromium + Node.js」 です。
- Chromium: Google Chromeのオープンソース版。HTMLをレンダリングするブラウザエンジン
- Node.js: サーバーサイドJavaScriptランタイム。ファイルシステムやOS APIにアクセス可能
この2つを組み合わせることで、「Webの技術でデスクトップアプリを作る」ことが可能になります。
2.2 Chromiumとは何か—なぜReactでUIが作れるのか
Web開発者は普段ブラウザを「使う側」なので、内部構造を意識することは少ないかもしれません。しかし、ElectronでReactが使える理由を理解するには、Chromiumの構成要素を知ることが重要です。
graph TB
subgraph Chrome["Google Chrome"]
ChromeFeatures["Chrome固有機能<br/>同期・アカウント・自動更新"]
subgraph Chromium["Chromium"]
Blink["Blink<br/>HTMLレンダリング"]
V8["V8<br/>JavaScript実行"]
Compositor["Compositor<br/>画面合成"]
Network["Network Stack<br/>HTTP通信"]
end
end
ChromeFeatures --> Chromium
| コンポーネント | 役割 | Electronとの関係 |
|---|---|---|
| Blink | HTML/CSSをパースして描画する(レンダリングエンジン) | ReactのJSXがDOMとして描画される |
| V8 | JavaScriptを実行する(Node.jsでも使われている) | Reactのロジックが動作する |
| Compositor | レイヤーを合成して最終的な画面を作る | アニメーションが滑らかに動く |
| Network Stack | HTTP/HTTPS通信を処理する | APIリクエストが動作する |
要するに:ElectronはChromium(ブラウザエンジンそのもの)をアプリに内蔵しているので、Webと同じ品質でUIを描画でき、React/Vue/Svelteなど好きなフレームワークがそのまま使えます。
なぜElectronアプリは容量が大きいのか
Chromiumを丸ごと含んでいるため、120〜200MB程度になるのが一般的です。最適化(不要なnode_modulesの除外、asar圧縮等)により80〜120MB程度まで削減できますが、これがElectronの「Webと同じ描画品質」「クロスプラットフォームでの一貫した動作」というメリットとのトレードオフです。
アプリサイズを重視する場合は、Tauri(3〜10MB程度)等の軽量な代替も検討してください。
2.3 プロセスモデル
Electronアプリは複数のプロセスで構成されます。
graph TB
subgraph MainProcess["Main Process"]
MainThread["Main Thread"]
NodeAPIs["Node.js APIs<br/>ファイル操作・OS API"]
ElectronAPIs["Electron APIs<br/>BrowserWindow等"]
end
subgraph RendererProcess["Renderer Process"]
BrowserWindow["Browser Window"]
ReactApp["React App"]
WebAPIs["Web APIs・DOM"]
end
subgraph PreloadScript["Preload Script"]
ContextBridge["contextBridge"]
ExposedAPIs["公開されたAPI"]
end
MainProcess <-->|"IPC通信"| PreloadScript
PreloadScript <-->|"安全なAPI公開"| RendererProcess
style MainProcess fill:#e1f5fe
style RendererProcess fill:#fff3e0
style PreloadScript fill:#f3e5f5
| プロセス | 役割 | 使える技術 |
|---|---|---|
| Main Process | アプリのエントリポイント。ネイティブ機能を担当 | Node.js全API、Electron API |
| Preload Script | Main↔Renderer間の橋渡し。セキュアなAPI公開 | 限定的なNode.js API |
| Renderer Process | UIの描画。1つのBrowserWindowにつき1つ | Web API、DOM、React等 |
なぜプロセスが分離されているのか
Main ProcessとRenderer Processは完全に別のプロセスです。メモリ空間も分離されています。
RendererからNode.js APIを直接呼び出すことはできません。これはセキュリティ上の理由です。
もしRendererがNode.jsに直接アクセスできたら、悪意のあるWebコンテンツがファイルシステムを操作できてしまいます。そのため、プロセス間の通信にはIPC(Inter-Process Communication) を使う必要があります。
2.4 Preloadスクリプトの役割
Preloadスクリプトは、Main ProcessとRenderer Processの安全な橋渡し役です。
Renderer Processは基本的にWebページと同じサンドボックス環境で動作します。そのままではNode.js APIにアクセスできません。しかし、アプリとしてファイル操作などのネイティブ機能を使いたい場面は多々あります。
そこでPreloadスクリプトの出番です。Preloadスクリプトは以下の特徴を持ちます:
- Renderer Processのコンテキストで実行されるが、一部のNode.js APIにアクセスできる
contextBridgeAPIを使って、Renderer側に必要なAPIだけを公開できる- Main Processとの通信(IPC)を安全にラップできる
これにより、「Rendererには最小限のAPIだけ見せる」という原則を守りつつ、ネイティブ機能を利用できます。
3. electron-shadcn テンプレート
3.1 なぜこれを選んだか
electron-shadcn を選んだ理由:
| 理由 | 説明 |
|---|---|
| Electron Forge | ビルド・パッケージングが統合されている |
| shadcn-ui | 慣れたUIコンポーネント。カスタマイズ性が高い |
| 型安全IPC(oRPC) | Main↔Renderer間の通信が型安全 |
| モダンスタック | Vite、TanStack Router/Query、Tailwind CSS 4 |
以前はElectronアプリを配布しようとすると、パッケージング、インストーラー生成、コード署名など、複数のツールを自分で組み合わせる必要がありました。Electron ForgeはElectronチームがメンテナンスしているツールチェーンで、それらを統合してくれています。
3.2 oRPCによる型安全なIPC
electron-shadcnでは、IPC通信にoRPCが採用されています。oRPCは以下の特徴を持つRPCフレームワークです:
- Zodスキーマ統合: 入出力のランタイム検証が可能
- 型推論: スキーマから自動的にTypeScript型を推論
- トランスポート非依存: MessagePort、WebSocket等に対応
具体例:IPCハンドラの定義
// src/ipc/example/schemas.ts import { z } from "zod"; export const GetUserInput = z.object({ id: z.string(), }); export const GetUserOutput = z.object({ id: z.string(), name: z.string(), });
// src/ipc/example/handlers.ts import { os } from "@orpc/server"; import { GetUserInput, GetUserOutput } from "./schemas"; export const getUser = os .input(GetUserInput) .output(GetUserOutput) .handler(async ({ input }) => { // Main Processでの処理 const user = await db.findUser(input.id); return user; });
// src/actions/user.ts(Renderer側) import { orpc } from "./client"; // 型安全な呼び出し - 入力・出力ともに型チェックされる const user = await orpc.getUser({ id: "123" }); // user.name 等が型補完される
型安全性の範囲
oRPCの型安全性は以下をカバーします:
- コンパイル時: TypeScriptによる静的型チェック
- ランタイム: Zodによる入出力の検証(不正なデータはエラーになる)
ただし、IPC通信自体のシリアライゼーション(JSON.stringify/parse)で失われる型情報(Date、Map、Set等)には注意が必要です。
他の選択肢
electron-trpc、typesafe-ipc、interprocess等の選択肢もあります。既存のプロジェクトで別のRPCライブラリを使っている場合は、そちらに置き換えることも可能です。
3.3 テックスタック
主要技術
| 技術 | 役割 | 選定理由 |
|---|---|---|
| Electron 39 | デスクトップアプリフレームワーク | Chromium + Node.js統合 |
| Vite 7 | ビルドツール | 高速なHMR |
| React 19 | UIライブラリ | React Compiler対応 |
| TypeScript 5.9 | 型システム | 型安全な開発 |
| TanStack Router | ルーティング | 型安全、ファイルベース |
| TanStack Query | サーバー状態管理 | キャッシュ、自動再フェッチ |
| oRPC | IPC通信 | 型安全RPC、Zod統合 |
| Zod 4 | スキーマバリデーション | ランタイム型検証 |
| Electron Forge | ビルド・パッケージング | Electronチームメンテナンス |
| shadcn/ui | UIコンポーネント | カスタマイズ性、アクセシビリティ |
| Tailwind CSS 4 | スタイリング | ユーティリティファースト |
補足:テンプレートのバージョンについて
上記のバージョンは2025年12月時点のelectron-shadcnテンプレート(v1.2.0)に基づいています。テンプレートは活発にメンテナンスされており、バージョンは随時更新されます。最新の情報はGitHub READMEを確認してください。
3.4 ディレクトリ構成
テンプレートデフォルト
src/ ├── actions/ # Renderer側IPCアクション ├── assets/ # フォント等の静的ファイル ├── components/ │ └── ui/ # shadcn-uiコンポーネント ├── constants/ # 定数定義 ├── ipc/ # IPC設定(oRPC) │ ├── theme/ # テーマ切り替え │ └── window/ # ウィンドウ操作 ├── layouts/ # レイアウトコンポーネント ├── localization/ # i18n設定 ├── routes/ # TanStack Routerルート定義 ├── styles/ # グローバルスタイル ├── tests/ # テストファイル ├── types/ # 型定義 └── utils/ # ユーティリティ関数
4. 開発フロー
4.1 セットアップ
git clone https://github.com/LuanRoger/electron-shadcn.git my-app cd my-app npm install npm run start
これでホットリロード対応の開発サーバーが起動します。
4.2 UIモック
Lovable / v0 → shadcn-uiトレース
- Lovableや v0 でUIモックを生成
- shadcn-uiベースなので、electron-shadcnテンプレートに移植しやすい
- 必要に応じてカスタマイズ
4.3 ビルドとパッケージング
# 開発用パッケージ作成 npm run package # 配布用インストーラー作成(.exe, .dmg等) npm run make # GitHub Releasesに公開 npm run publish
4.4 GitHub Actionsでのリリース自動化
name: Release on: push: tags: - "v*" jobs: release-macos: runs-on: macos-latest permissions: contents: write steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 cache: "npm" - run: npm ci - run: npm run publish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
v1.0.0 などのタグをプッシュすると、自動でビルド → GitHub Releasesに公開されます。
⚠️ クロスプラットフォーム対応の注意点
上記の例はmacOS版のみです。Windows/Linuxもサポートする場合:
jobs: release: strategy: matrix: os: [macos-latest, windows-latest, ubuntu-latest] runs-on: ${{ matrix.os }} # ... 以下同様
プラットフォーム固有の問題にも注意が必要です:
- パスの区切り文字:
path.join()を使い、ハードコードを避ける - ファイルシステムの大文字小文字: macOS(デフォルト)は区別しないが、Linuxは区別する
- ネイティブモジュール:
better-sqlite3等を使う場合、各プラットフォームでrebuildが必要
5. 配布時の注意点
開発段階ではElectron Forgeのおかげでスムーズに進められますが、本番配布となると追加の作業と費用が必要です。ここは開発を始める前に把握しておくべき重要なポイントです。
5.1 コード署名と公証
アプリを一般ユーザーに配布する場合、コード署名が事実上必須です。
| OS | 必要なもの | コスト(目安) |
|---|---|---|
| macOS | Apple Developer Program + 公証 | 年額 $99 |
| Windows | EV コード署名証明書 | 年額 $200〜500程度(発行元により異なる) |
署名なしでも開発・テストは可能ですが、配布時には「開発元を確認できません」等の警告が表示され、ユーザー体験を損ないます。
Windows EV証明書の補足
Windows向けEV(Extended Validation)コード署名証明書は、費用だけでなく取得プロセスも考慮が必要です。法人格の確認、ハードウェアトークン(USBドングル)の受け取りなど、個人開発者にとっては障壁となる場合があります。OV(Organization Validation)証明書はより安価ですが、SmartScreen警告を回避するには実績が必要です。
詳細はElectronのコード署名ガイドを参照してください。
5.2 自動アップデート
electron-shadcnはupdate-electron-appによる自動アップデートをサポートしています。GitHub Releasesを使った基本的な設定はテンプレートに含まれていますが、本番運用には追加の設定が必要になる場合も。
注意: 自動アップデート機能は、オープンソースリポジトリでGitHub Releasesを使う場合にのみ無料で利用できます。プライベートリポジトリの場合は、カスタムアップデートサーバーのセットアップが必要です。
詳細はElectronのアプリケーション更新ガイドを参照してください。
6. まとめ
Electronの仕組み
graph LR
Electron["Electron"]
Chromium["Chromium<br/>HTML描画"]
NodeJS["Node.js<br/>ネイティブ機能"]
Electron --- Chromium
Electron --- NodeJS
- Main Process: Node.js API、ネイティブ機能を担当
- Renderer Process: Chromiumでhtml描画、React等のUIフレームワーク
- Preload Script: セキュアなAPI公開(contextBridgeで必要なAPIだけ露出)
- IPC: プロセス間通信(型安全に行うのが重要)
electron-shadcnの良さ
- Web開発者に馴染みのあるスタック(React 19、shadcn-ui、TanStack)
- 型安全なIPC(oRPC + Zod)
- ビルド・パッケージングの統合(Electron Forge)
Web開発の経験があれば、Electronでの開発自体はスムーズに始められます。
一般配布については、コード署名のコストなど追加の課題がありますが、Electron Forgeのおかげでビルド・パッケージングのハードルは以前より下がっています。
参考リンク
- Electron 公式ドキュメント
- Electron セキュリティガイド
- Electron コード署名ガイド
- electron-shadcn テンプレート
- Electron Forge
- oRPC
- oRPC Electron Adapter
- shadcn/ui
- Tauri
- 【翻訳】テスト駆動開発の定義 - t-wadaのブログ(スクリーンショット内のナレッジ素材)
- LAPRAS Tech News Talk #184(スクリーンショット内の音声解析素材)