create-react-appで楽にReact+Electronアプリを書けるようになりました。("How to build an Electron app using Create React App and Electron Builder")
それをさらに推し進め、より安全・快適なReact+Electronアプリ開発環境を構築してみます。(長い)タイトルにある通り、目標は以下の通りです。
- create-react-appでTypeScript対応プロジェクトをさくっと生成
- Main Processでも、すべてのコードをTypeScriptを書く
- Main Processでも、Hot Reloadで生産性をアップ
- パッケージングはelectron-builderで簡単に
手順
プロジェクトの作成
npx create-react-app my-app --typescript
yarn add electron-is-dev electron-reload
yarn add -D concurrently electron electron-builder wait-on
Main Process
ディレクトリの作成
mkdir electron
tsconfig.json
create-react-app付属の yarn build
スクリプトと同様、build
ディレクトリに生成物を出力するようoutDir
を設定します。
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"sourceMap": true,
"strict": true,
"outDir": "../build",
"rootDir": "../",
"noEmitOnError": true,
"typeRoots": [
"node_modules/@types"
]
}
}
main.ts
基本的にElectronのサイトにあるサンプルをTypeScript化し、Hot Reloadのコード追加します。
import { app, BrowserWindow } from 'electron';
import * as path from 'path';
import * as isDev from 'electron-is-dev';
let win: BrowserWindow | null = null;
function createWindow() {
win = new BrowserWindow({ width: 800, height: 600 })
if (isDev) {
win.loadURL('http://localhost:3000/index.html');
} else {
// 'build/index.html'
win.loadURL(`file://${__dirname}/../index.html`);
}
win.on('closed', () => win = null);
// Hot Reloading
if (isDev) {
// 'node_modules/.bin/electronPath'
require('electron-reload')(__dirname, {
electron: path.join(__dirname, '..', '..', 'node_modules', '.bin', 'electron'),
forceHardReset: true,
hardResetMethod: 'exit'
});
}
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (win === null) {
createWindow();
}
});
以下の部分がHot Reloadの対応コードです。
// Hot Reloading
if (isDev) {
// 'node_modules/.bin/electronPath'
require('electron-reload')(__dirname, {
electron: path.join(__dirname, '..', '..', 'node_modules', '.bin', 'electron'),
hardResetMethod: 'exit'
});
}
package.jsonの調整
Electron化に必要なプロパティの追加
"homepage": ".",
"main": "build/electron/main.js",
homepage
でRender Process内のpath指定をrelativeにし、main
でMain Processのエントリポイントを指定。
Electron Builderに必要なプロパティの追加
"author": "Your Name",
"description": "...",
"build": {
"extends": null,
"files": [
"build/**/*"
],
"directories": {
"buildResources": "assets"
}
},
create-react-appはMain Processのエントリポイントを強制的にpublic/electron.js
に変更してしまうので、extends
にnull
をセットして無効化します。(https://github.com/electron-userland/electron-builder/issues/2030)
create-reac-appはビルド結果をbuild
ディレクトリに出力しますが、 electoron-builderもリソースファイルをbuild
ディレクトリに保存しようとします。それでbuildResources
を指定して保存先を変更します。
npm scriptの追加
"scripts": {
"postinstall": "electron-builder install-app-deps",
"electron:dev": "concurrently \"BROWSER=none yarn start\" \"wait-on http://localhost:3000 && tsc -p electron -w\" \"wait-on http://localhost:3000 && tsc -p electron && electron .\"",
"electron:build": "yarn build && tsc -p electron && electron-builder",
electron:dev
が開発用スクリプトで、Main/Render Process共にHot Relaodに対応しています。まずReactプロジェクトをビルドし、開発用サーバーを立ち上げます。その後Main Processのコードをビルドし、開発モードのelectronアプリを起動します。またHot Reloadのためにtsc
をwatchモードで起動します。
electron:build
でDistribution Packageをビルドします。生成されたパッケージはdist
ディレクトリに保存します。パッケージ化されていないアプリそのものだけをビルドしたい場合は、yarn electron:build --dir
とします。
postinstall
は直接起動することはありません。yarn install
後に、インストールされているElectronが使用するのと同じバージョンのNativeモジュールをインストールします。
ディレクトリ構成の概要
my-app/
├── package.json
│
## render process
├── tsconfig.json
├── public/
├── src/
│
## main process
├── electron/
│ ├── main.ts
│ └── tsconfig.json
│
## build output
├── build/
│ ├── index.html
│ ├── static/
│ │ ├── css/
│ │ └── js/
│ │
│ └── electron/
│ └── main.js
│
## distribution packges
└── dist/
├── mac/
│ └── my-app.app
└── my-app-0.1.0.dmg
まとめ
以下が今回のコード(+α)です。
https://github.com/yhirose/react-typescript-electron-sample-with-create-react-app-and-electron-builder
TypeScriptの安心感とHot Reloadの快適さで、さらに楽しく開発しましょう!