49
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

create-react-appとelectron-builderでTypeScriptとHot Reloadに完全対応したElectronアプリ開発環境を作成する

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を設定します。

electron/tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "sourceMap": true,
    "strict": true,
    "outDir": "../build",
    "rootDir": "../",
    "noEmitOnError": true,
    "typeRoots": [
      "node_modules/@types"
    ]
  }
}

main.ts

基本的にElectronのサイトにあるサンプルをTypeScript化し、Hot Reloadのコード追加します。

electron/main.ts
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化に必要なプロパティの追加

package.json
  "homepage": ".",
  "main": "build/electron/main.js",

homepageでRender Process内のpath指定をrelativeにし、mainでMain Processのエントリポイントを指定。

Electron Builderに必要なプロパティの追加

package.json
  "author": "Your Name",
  "description": "...",
  "build": {
    "extends": null,
    "files": [
      "build/**/*"
    ],
    "directories": {
      "buildResources": "assets"
    }
  },

create-react-appはMain Processのエントリポイントを強制的にpublic/electron.jsに変更してしまうので、extendsnullをセットして無効化します。(https://github.com/electron-userland/electron-builder/issues/2030)

create-reac-appはビルド結果をbuildディレクトリに出力しますが、 electoron-builderもリソースファイルをbuildディレクトリに保存しようとします。それでbuildResourcesを指定して保存先を変更します。

npm scriptの追加

package.json
  "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の快適さで、さらに楽しく開発しましょう!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
49
Help us understand the problem. What are the problem?