Create React App(typescript)をベースにelectron環境を構築する
Create React App(typescript)をベースにelectronの環境を構築する手順メモ。Windows環境でのみ検証。
Create React App
Create React Appを実行する。
npx create-react-app electronapp --template typescript
npm install
Create React Appで作ったプロジェクトにelectronに必要なパッケージをインストールしていく。
cd electronapp
npm i -D concurrently cross-env electron electron-builder wait-on
electron/electron.ts
electronディレクトリを作ってメインファイルを作成する。electronフォルダからbuildフォルダにビルドして利用する前提。
mkdir electron
electronのmainファイル。やっていることは、ほぼelectronのチュートリアルのまま。
app.isPackagedを使って、dev環境ではlocalhostを読み込みつつdevコンソールを開くように設定。
import { app, BrowserWindow } from "electron";
import * as path from "path";
import * as url from "url";
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
});
const appURL = app.isPackaged
? url.format({
pathname: path.join(__dirname, "../index.html"),
protocol: "file:",
slashes: true,
})
: "http://localhost:3000";
win.loadURL(appURL);
if (!app.isPackaged) {
win.webContents.openDevTools();
}
};
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
app.whenReady().then(() => {
createWindow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
electron/preload.ts
preload.tsを作成し、メインプロセスとレンダラーをつなぐためにcontextBridgeを作っておく。詳細は後ほど説明。
import { contextBridge } from "electron";
contextBridge.exposeInMainWorld("myAPI", {
counter: (count: number) => {
return count + 1;
},
});
electron/tsconfig.json
electronのメインプロセス用のtsconfig.json。reactに使うプロジェクトルートにあるものと別に作成する。rootDir
を'../'
にすることで build/electron/*
として出力される。
electronのパッケージを作るときは、buildフォルダはCreate React Appと共通で使うので要注意。
{
"compilerOptions": {
"target": "ESNext",
"module": "commonjs",
"sourceMap": true,
"outDir": "../build",
"rootDir": "../"
},
"include": ["*"]
}
package.jsonを編集
package.json
にmain
とhomepage
を追加。mainはビルド後のjsファイルを指定。
+"main": "build/electron/electron.js",
+"homepage": "./",
ついでにbrowserslist
をproduction・development両方とも"last 1 electron version"
のみに変更
"browserslist": {
"production": [
+ "last 1 electron version",
- ">0.2%",
- "not dead",
- "not op_mini all"
],
"development": [
+ "last 1 electron version",
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
]
},
public/index.htmlを編集
public/index.htmlのheadにCSPのmetaタグを追加。
<head>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
package.jsonにscriptsを追加
package.jsonにscriptsにdev用のscriptsを追加。
"scripts": {
+ "electron:dev": "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://localhost:3000 && tsc -p electron -w\" \"wait-on http://localhost:3000 && tsc -p electron && electron .\""
dev環境の立ち上げテスト
npm run electron:dev
ここでdev環境を立ち上げると、CRAのスタートページがelectron上で表示される。
レンダラーとメインプロセスをつなぐ
次は、メインプロセスとはreact(レンダラー)をつなぐ。
preload.ts側でcontextBridge.exposeInMainWorld
に登録すると、react側でwindow.myAPI.counter
のように使えるようになる。
テストとして、メインプロセス側でカウンターを作ってをれをreactから呼び出してみる。
preload側でカウンターを作成する。
import { contextBridge } from "electron";
contextBridge.exposeInMainWorld("myAPI", {
counter: (count: number) => {
return count + 1;
},
});
App.tsx側はwindow.myAPI.counter(count)
で呼び出す。
import React, { useState } from "react";
import logo from "./logo.svg";
import "./App.css";
function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>{count}</p>
<button
onClick={() => {
console.log();
setCount(window.myAPI.counter(count));
}}
>
count
</button>
</header>
</div>
);
}
export default App;
このままだと、windowにmyAPIが無いと怒られるので、src/@types/global.d.ts
を作り、型を拡張しておく
export declare global {
interface Window {
myAPI: {
counter: (count: number) => number;
};
}
}
dev環境でメインプロセスとレンダラーの通信を確認
レンダラー側でcountボタンを押すと、メインプロセスで計算して、またレンダラー側で受け取って描画しているのが確認できる。
ビルドしてアプリを作る(windows)
最後にビルドしてelectronのアプリを作る。windowsしか確認できていません……
package.jsonにbuildを追加する。設定内容は、「Electronで1からデスクトップアプリを作り、electron-builderを使ってビルド・リリースするまで」が詳しいのでこちらを参考ください。
+ "build": {
+ "extends": null,
+ "files": [
+ "build/**/*"
+ ],
+ "directories": {
+ "buildResources": "assets"
+ }
+ }
scriptsにインストールせずに使えるポータブルアプリ用の"electron:build:portable"
とインストールアプリの"electron:build:nis"
をpackage.jsonのscriptsに追加する。
"scripts": {
+ "electron:build:portable": "npm run build && tsc -p electron && electron-builder --win --x64 --dir",
+ "electron:build:nis": "npm run build && tsc -p electron && electron-builder --win --x64"
アプリはdistフォルダにビルドされるので.gitignoreにdistを追加。
+dist
これでelectronアプリができているのが確認出来ると思います。
参考リンク
Discussion