Warning: Undefined variable $position in /home/pystyles/pystyle.info/public_html/wp/wp-content/themes/lionblog/functions.php on line 4897

Electron – Electron + React で GUI アプリを作成する

Electron – Electron + React で GUI アプリを作成する

概要

React を使用して作成したページを Electron で使用する方法について解説します。

本記事で紹介するコードは以下を参照ください。

electron-examples/09_electron-use-react/react-electron

手順

1. React プロジェクトを作成する

React プロジェクトを create-react-app を使用して作成します。

npx create-react-app react-electron --template typescript

npm start で React が正常にインストールできたかどうかを確認します。React のページがブラウザに表示されたら成功です。現時点のディレクトリ構成は以下のようになっています。

react-electron
├── node_modules
├── package-lock.json
├── package.json
├── public
├── README.md
├── src
└── tsconfig.json

2. Electron をインストールする

Electron の他、開発時に必要となるモジュールをインストールします。

npm install -D electron cross-env wait-on concurrently
  • electron: Electron
  • cross-env: 環境変数を設定してコマンドを実行するのに使用
  • wait-on: ページにアクセスできるようになってからコマンドを実行するのに使用
  • concurrently: 複数のコマンドを並列に実行できるようにするために使用

electron というディレクトリを作成し、その配下に main.ts 及び tsconfig.json を作成します。

react-electron
├── electron <-- 新規作成
|  ├── main.ts
|  └── tsconfig.json
├── electron
├── node_modules
├── package-lock.json
├── package.json
├── public
├── README.md
├── src
└── tsconfig.json

main.ts

import { app, BrowserWindow } from "electron";

const createWindow = () => {
  const win = new BrowserWindow();
  win.loadURL("http://localhost:3000/");
};

app.whenReady().then(createWindow);
  • Electron に表示するページを react-scripts start を実行すると表示される URL http://localhost:3000/ に設定します。

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "outDir": "../build",
    "module": "commonjs",
    "strict": true,
    "rootDir": "../"
  }
}
  • ビルド生成物が react-electron/build/ 以下になるように、"outDir": "../build" を指定します

3. package.json を編集する

package.json を編集して、以下の2点を追記します。

  1. react-electron/electron/main.ts をコンパイルして生成される react-electron/build/main.js をエントリポイントに指定するため、"main": "build/electron/main.js" を追記します
  2. Electron を起動する "electron:start": "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://127.0.0.1:3000 && tsc -p electron && electron .\"" を追記します

electron:start では、concurrently を使用して、以下の2つのコマンドを並列実行しています。

  1. "cross-env BROWSER=none npm start" で React アプリを起動し、http://127.0.0.1:3000 でアクセスできるようにします
    • 環境変数 BROWSER=none を設定すると、react-scripts start 時にブラウザが開かれません
    • 環境変数を指定してコマンドを実行するために cross-env を使用しています
  2. wait-on http://127.0.0.1:3000 && tsc -p electron && electron .\ で、react-electron/electron 配下のファイルをコンパイルし、Electron を起動します
    • wait-on http://127.0.0.1:3000 で、npm start により React のページにアクセスできるようになるのを待ってから、後続のコマンドを実行します

4. Electron を起動する

Electron を起動し、React のページがウィンドウに表示されたら成功です。

npm run electron:start

パッケージ化する

electron-builder でパッケージ化するための方法を紹介します。

1. electron-builder をインストール

npm install -D electron-builder

2. main.ts を編集する

npm run build (react-scripts build) を実行すると、./build/index.html が生成されます。 パッケージ化されている場合、読み込むファイルは ./build/index.html となるように変更します。

main.ts

import { app, BrowserWindow } from "electron";

const createWindow = () => {
  const win = new BrowserWindow();
  win.webContents.openDevTools();

  if (app.isPackaged) {
    win.loadURL(`file://${__dirname}/../index.html`);
  } else {
    win.loadURL("http://localhost:3000/");
  }
};

app.whenReady().then(createWindow);

3. package.json を編集する

ビルド設定を追加する

package.json を編集します。まず、electron-builder のビルド設定を追加します。

"build": {
  "files": [
    "build/**/*"
  ],
  "extends": null
},

コマンドを追加する

コマンド "electron:build": "npm run build && tsc -p electron && electron-builder" を追加します。 このコマンドは以下の処理を順番に行います。

  1. npm run build (react-scripts build) により、React アプリをビルドする。ビルド結果は ./build に出力される。
  2. tsc -p electron により、./electron 以下の Electron 関係のファイルをビルドする。ビルド結果は ./build に出力される。
  3. electron-builder でパッケージ化する

リソースファイルを相対パスで記述する

file:// プロトコルのルートは、file:///C: のようにドライブのルートになってしまうため、index.html 内で /statis/sample.js と記述されていても、file:///C:/statis/sample.js を見に行ってしまい、リソースファイルにアクセスできません。 リソースファイルのパスを index.html があるディレクトリからの相対パスにするために、package.json"homepage": "./", を追加します。 これにより、react-scripts build により生成される index.html が読み込む各種リソースファイルのパスが index.html からの相対パスになります。

変更前に react-scripts build で生成した index.html

<script defer="defer" src="/static/js/main.cc475e7b.js"></script>
<link href="/static/css/main.f855e6bc.css" rel="stylesheet" />

↓ 変更後に react-scripts build で生成した index.html

<script defer="defer" src="//static/js/main.cc475e7b.js"></script>
<link href="//static/css/main.f855e6bc.css" rel="stylesheet" />

上記を追記した状態の package.json は以下のようになっているはずです。

{
  "name": "react-electron",
  "version": "0.1.0",
  "private": true,
  "main": "build/electron/main.js",
  "homepage": "./",
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.2",
    "@types/node": "^16.18.73",
    "@types/react": "^18.2.48",
    "@types/react-dom": "^18.2.18",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "typescript": "^4.9.5",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "electron:start": "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://127.0.0.1:3000 && tsc -p electron && electron .\"",
    "electron:build": "npm run build && tsc -p electron && electron-builder"
  },
  "build": {
    "files": [
      "build/**/*"
    ],
    "extends": null
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "concurrently": "^8.2.2",
    "cross-env": "^7.0.3",
    "electron": "^28.1.4",
    "electron-builder": "^24.9.1",
    "wait-on": "^7.2.0"
  }
}

4. パッケージ化する

パッケージをビルドします。バイナリファイルは ./dist 以下に生成されます。

npm run electron:build