Electron ForgeでReact + Vite + TypeScriptのデスクトップアプリ開発環境構築
2023/05/22
Table of Contents
はじめに
Electron Forgeはテンプレートからのプロジェクト作成や、アプリ配布のための便利なツールです。
今回はViteテンプレートを使ってTypeScriptとReact環境でデスクトップアプリを動かせるようになるまでの手順を紹介します。
環境
- Node 18.7.0
- TypeScript 5.0.4
- Electron Forge 6.1.1
- Electron 24.3.0
プロジェクト作成
まずはElectron Forgeの electron-app
コマンドを使ってプロジェクト作成をします。
テンプレートはViteを指定します。
$ npm init electron-app@latest electron-vite-react-app -- --template=vite
TypeScriptに書き換える
生成されたプロジェクトはデフォルトだとJavaScriptで書かれたもののため、TypeScriptに書き換えます。
まず作成された.jsファイルを.tsファイルに書き換えました。以下を書き換えました。
- vite.main.config.ts
- vite.preload.config.ts
- vite.renderer.config.ts
- src/main.ts
- src/renderer.ts
- src/preload.ts
forge.config.jsだけは書き換えてしまうと、動かなくなってしまうのでそのままにしました。
そしてそのforge.config.jsとindex.htmlには各エントリファイルの設定が書かれているので、それも.tsに修正します。
module.exports = {
// 省略
plugins: [
{
name: '@electron-forge/plugin-vite',
config: {
build: [
{
entry: 'src/main.ts',
config: 'vite.main.config.ts',
},
{
entry: 'src/preload.ts',
config: 'vite.preload.config.ts',
},
],
renderer: [
{
name: 'main_window',
config: 'vite.renderer.config.ts',
},
],
},
},
],
};
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World!</title>
</head>
<body>
<h1>💖 Hello World!</h1>
<p>Welcome to your Electron application.</p>
<script type="module" src="/src/renderer.ts"></script>
</body>
</html>
あとはsrc/main.tsのグローバル変数の型も用意する必要がありました。
declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string;
declare const MAIN_WINDOW_VITE_NAME: string;
tsconfig.jsonの用意
TypeScriptに書き換えたので、tscコマンドで型チェックを行うためにtsconfig.jsonを用意します。
{
"compilerOptions": {
"target": "ESNext",
"allowJs": true,
"module": "ESNext",
"skipLibCheck": true,
"esModuleInterop": true,
"noImplicitAny": true,
"baseUrl": ".",
"noEmit": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"strict": true
},
}
最後にpackage.jsonに型チェックコマンドを追加して、CIなどでチェックするようにすればOKです。
$ npm install -D typescript
{
.
.
"scripts": {
.
.
"type:check": "tsc"
},
.
.
}
以下コマンドで型のチェックが走ります。
$ npm run type:check
Reactの導入
基本的に以下ドキュメント通りで問題ありませんでした。
インストール
npm install react react-dom
npm install -D @types/react @types/react-dom
app.tsx作成
import * as ReactDOM from 'react-dom';
function render() {
ReactDOM.render(<h2>Hello from React!</h2>, document.body);
}
render();
作成したapp.tsxをレンダラープロセスで呼び出すため、renderer.tsでインポートします。
import './app';
最後にtsconfig.jsonのcompilerOptionsに "jsx": "react-jsx"
を追加するのを忘れないでください。
これで npm start
を再度行うと、Reactが動いているのが確認できるはずです。
IPCまわりの型
メインプロセスとレンダラープロセスの通信ではIPCが使われますが、その際の型定義にも少し触れておきます。
例えばpreload.tsで以下のようなメソッドをレンダラープロセス側に用意するとします。
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
});
そしてメインプロセスでは
ipcMain.handle('dialog:openFile', handleFileOpen);
のような感じで処理を書くと思います。
その場合はレンダラープロセスrenderer.tsでは
const path = await window.electronAPI.openFile();
のように呼べるようになります。
ただ、本来windowオブジェクトにはelectronAPIなんてものはないので、グローバルに型宣言を追加で定義してあげる必要があります。
src/global.d.tsを用意してelectronAPIをwindowオブジェクトに追加してあげます。
declare global {
interface Window {
electronAPI: {
openFile: () => Promise<string>
};
}
}
export {}
これで型エラーにならずに、IPCの処理を書くことができました。
おわりに
今回はElectron Forgeを利用してプロジェクト作成、TypeScriptとReactの導入までを行いました。
IPCまわりは自前で型定義ファイルを用意しなければならなく、イケてないので、次回はelectron-trpcを使って型安全なIPCを実現したいと思います。