Contents
ElectronとReactの統合プロジェクトをTypeScriptで構築する意義
ElectronとReactを組み合わせたデスクトップアプリ開発は、フロントエンドエンジニアにとって非常に実用的な選択肢です。このアプローチの最大の強みは、Web技術の知識をほぼそのまま活かせる点と、TypeScriptによる型安全な開発環境が整う点です。特にElectronのメインプロセスとReactのレンダラープロセスを分離した構造では、TypeScriptの型定義がエラーの早期検出やコード品質向上に大きく貢献します。
Electronプロジェクトの初期設定手順
Electronアプリケーションの立ち上げは、公式CLIツールやテンプレートを使うことで効率化できます。以下に具体的な手順を解説します。
npx create-electron-appによるテンプレート生成
最新のElectron環境構築にはcreate-electron-appが推奨されます。このコマンドでプロジェクトを作成すると、既存のTypeScript設定やビルドスクリプトが自動的に導入されます。
-
プロジェクト作成
bash
npx create-electron-app my-electron-app --template=typescript -
ディレクトリ移動
bash
cd my-electron-app -
依存関係のインストール
bash
npm install
このテンプレートでは、tsconfig.jsonが自動生成され、Electron用のTypeScript環境が整います。
TypeScript環境の導入方法
テンプレートでTypeScriptが初期設定されている場合でも、以下のように補足設定を行うとより安定した開発環境になります。
-
tsconfig.jsonの編集:
targetをES2021に、moduleをESNextに設定します。
json
{
"compilerOptions": {
"target": "ES2021",
"module": "ESNext",
"strict": true,
"jsx": "react",
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist"
},
"include": ["src/**/*"]
} -
Node.jsモジュールの型定義:
@types/nodeをインストールします。
bash
npm install --save-dev @types/node
Reactアプリケーションとの接続方法
ElectronとReactを統合する際には、メインプロセス(Node.js環境)とレンダラープロセス(Web技術環境)の分離が不可欠です。以下に具体的なやり方を解説します。
create-react-appのTypeScriptテンプレート利用
Reactアプリケーションはcreate-react-appで初期化し、TypeScript設定を導入できます。最新バージョンではreact-scripts-tsは非推奨になったため、ViteやWebpackを使う方法が主流です。
-
Reactプロジェクトの作成
bash
npx create-react-app my-react-app --template typescript -
Electronと接続する準備:
my-electron-appディレクトリで、main.tsを編集し、レンダラープロセスにReactアプリを読み込むようにします。
typescript
import { app, BrowserWindow } from 'electron';
import * as path from 'path';
let mainWindow: BrowserWindow | null = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
|
1 2 |
mainWindow.loadURL('http://localhost:3000'); |
}
app.whenReady().then(createWindow);
メインプロセスとレンダラープロセスのバインディング
ElectronとReactを接続するには、preload scriptを使う方法が安全です。以下に具体的な実装手順を示します。
- preload.jsを作成:
javascript
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
send: (channel: string, data: any) => ipcRenderer.send(channel, data),
receive: (channel: string, callback: (data: any) => void) =>
ipcRenderer.on(channel, (_, data) => callback(data))
});
- Reactアプリ側で使用:
typescript
window.electronAPI.receive('from-main', (data) => {
console.log('Received from main process:', data);
});
window.electronAPI.send('to-main', { message: 'Hello from React!' });
TypeScriptでの型定義ファイル作成
Electronの動作に必要なTypeScriptの型定義ファイルを正しく導入するには、以下の手順を実施します。
Electronの型宣言ファイルのインストール手順
Electronのバージョンと一致した型定義を導入することで、開発時のエラーが抑えられます。
-
@types/electronの導入:
bash
npm install --save-dev @types/electron -
tsconfig.jsonに追加:
json
{
"types": ["electron", "node"]
} -
main.tsとrenderer.tsで型を活用:
メインプロセスではElectron.App、レンダラープロセスではElectron.WebContentsなどの型が自動的に補完されます。
カスタム型定義のベストプラクティス
独自に使用するIPCメッセージやAPIをTypeScriptで型定義することで、コード品質が向上します。
- カスタム型ファイル作成例:
src/types/ipc.d.ts
typescript
declare namespace Electron {
interface IpcMessage {
channel: string;
payload: any;
}
}
// メインプロセス側で使用
function sendIPC(message: Electron.IpcMessage): void;
// レンダラープロセス側で使用
function receiveIPC(callback: (message: Electron.IpcMessage) => void): void;
主要な設定と比較表
以下に、Electronプロジェクトにおける重要な設定項目を比較します。
| 設定項目 | 値 | 補足 |
|---|---|---|
| nodeIntegration | false |
セキュリティリスクの低減 |
| contextIsolation | true |
レンダラープロセスとメインプロセスの分離 |
| sandbox | true (推奨) |
レンダラープロセスのセキュリティ強化 |
| enableRemoteModule | false |
非推奨、セキュリティリスク |
blockquote: 上記の設定はElectronのセキュリティを確保するための基本的な設定です。特に
contextIsolationとsandboxの有効化が重要です。
メインプロセスとレンダラープロセスの通信実装
Electronでは、メインプロセスとレンダラープロセスの間でデータを送受信するためのAPIとしてIPC(Inter-Process Communication)があります。以下にTypeScriptでの実装方法を解説します。
ipcMain/ipcRendererのTypeScriptでの利用
ElectronのIPC機能は、electron/ipc-mainとelectron/ipc-rendererモジュールを使って実装できます。
- メインプロセス側(main.ts):
typescript
import { app, BrowserWindow } from 'electron';
import * as path from 'path';
import { ipcMain } from 'electron';
let mainWindow: BrowserWindow | null = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
|
1 2 3 4 5 6 7 8 |
mainWindow.loadURL('http://localhost:3000'); // IPCリスナーの登録 ipcMain.on('from-renderer', (event, data) => { console.log('Received from renderer:', data); event.reply('to-renderer', { message: 'Hello from main!' }); }); |
}
app.whenReady().then(createWindow);
- レンダラープロセス側(Reactアプリ):
typescript
window.electronAPI.send('from-renderer', { message: 'Hello from React!' });
window.electronAPI.receive('to-renderer', (data) => {
console.log('Received from main:', data);
});
セキュリティ考慮事項
IPC通信を安全に実装するには、以下のような注意点があります。
- IPCチャネルの制限: 無駄なIPCメッセージを送信しないように、使用可能なチャネル一覧を管理します。
typescript
const allowedChannels = ['from-renderer', 'to-renderer'];
ipcMain.on('ipc-message', (event, data) => {
if (!allowedChannels.includes(data.channel)) return;
// 実装
});
- Context Isolationの有効化: セキュリティリスクを抑えるために、
contextIsolation: trueに設定します。
開発環境とビルド環境の統合手順
ReactアプリケーションとElectronプロジェクトを統合するには、以下のようなステップが必要です。
- Reactアプリケーションの構築:
create-react-appでTypeScriptテンプレートを使用し、基本的なプロジェクトを作成します。 - Electronプロジェクトの設定:
create-electron-appでElectronプロジェクトを生成し、main.tsにReactアプリをロードするように設定します。 - ビルドプロセスの統合: Electron BuilderやWebpackを使ってReactアプリケーションとElectronプロジェクトを一緒にパッケージングします。
Electron Builderの使用に関する注意点
最新バージョンのElectron Builderでは、security設定項目は非推奨となっています。代わりに、asarやnodeIntegrationなどのセキュリティ関連のオプションを使用してください。
- 代替的なセキュリティ対策:
json
{
"build": {
"appId": "com.example.myapp",
"files": ["dist/**/*", "main.js"],
"win": {
"target": "nsis"
},
"asar": true
}
}
結論とまとめ
本記事では、ElectronとReactを統合したTypeScriptプロジェクトの構築方法について詳細に解説しました。以下が主要なポイントです。
- 初期設定:
create-electron-appやcreate-react-appを活用し、TypeScript環境を整える - 接続方法: preload script経由でメインプロセスとレンダラープロセスを連携する
- 型定義:
@types/electronやカスタム型ファイルで開発品質を向上させる - IPC通信:
ipcMain/ipcRendererを使うことで安全なデータ送信が可能になる - パッケージ管理: バージョンロックやセキュリティオプションで安定した環境を作成する
ElectronとReactを組み合わせた開発は、デスクトップアプリの実装に最適な技術スタックです。TypeScriptを使うことで型安全が確保され、長期的な保守性が向上します。今後も最新のトピックを追って更新していきます。