以下の内容はhttps://techblog.raksul.com/entry/2025/12/14/120000より取得しました。


electron-shadcnを使ったモダンデスクトップアプリ開発

title

ノバセル株式会社 MKPLA開発部 のTamtamです。

この記事はノバセル テクノ場 出張版2025 Advent Calendar 2025の14日目になります。

はじめに

ソフトウェア開発において、コーディングやコードレビューの領域ではAI活用が進んでいますが、「仕様を決める会議」や「設計を議論するミーティング」といったプランニング段階では、まだ十分に活用されていないと感じていました。そこで、会議中の会話をリアルタイムで解析し、議論の支援を行うAIアシスタントを個人開発で作ることにしました。音声をその場で文字起こしし、会話の文脈から見落としている論点やリスクをAIが能動的にサジェストするアプリです。

デスクトップアプリを選んだのは、ZoomやMeetといった会議ツールと併用しながらサジェストを常に視界に入れておきたかったからです。ElectronならBrowserWindowalwaysOnTopオプションでウィンドウを最前面に固定できますが、Webアプリにはこの手段がありません。また、マイク入力とシステム音声を同時に扱う場面でも、ブラウザでは毎回許可ダイアログが必要で画面共有と一緒でないとシステム音声が取れませんが、ElectronのdesktopCapturer APIなら音声ソースを個別に指定できます。

トップ画面(素材の出典:【翻訳】テスト駆動開発の定義 - t-wadaのブログ

サジェストウィンドウ(素材の出典:LAPRAS Tech News Talk #184

普段は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にアクセスできる
  • contextBridge APIを使って、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トレース

  1. Lovableや v0 でUIモックを生成
  2. shadcn-uiベースなので、electron-shadcnテンプレートに移植しやすい
  3. 必要に応じてカスタマイズ

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のおかげでビルド・パッケージングのハードルは以前より下がっています。


参考リンク




以上の内容はhttps://techblog.raksul.com/entry/2025/12/14/120000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14