はじめに
「チュートリアル:Reactの導入」を一通り終えたとき、完成したコードをElectronで動かしたくなった。そこで、Parcelを使ってシンプルに構成してみる。webpack.config.js
は書きたくない。
完成品
ビルドはしていない。
https://github.com/Hellokichi/electron-react-tutorial
環境
- windows 11 Pro
- node.js 16.15.0
- electron 19.0.0
- react 18.1.0
- parcel-bunlder 1.12.5
ディレクトリ構成
./
├ node_modules/
├ parceled/
│ ├ index.html
│ ├ src.js
│ └ src.css
├ dist/
│ └ react_tutorial 1.0.0.exe
├ electron/
│ ├ main.js
│ └ preload.js
└ react/
├ public/
│ └ index.html
└ src/
├ index.js
└ index.css
最終的なディレクトリ構成(一部省略)。
ParcelでビルドしたHTMLファイル、JSファイル、CSSファイルをparceled
に出力して、それらをelectron-builderでビルドしてdist
に実行ファイル形式で出力するイメージ。
パッケージのインストール
npm i -D react react-dom
npm i -D electron electron-builder
npm i -g parcel-bundler
レンダラープロセス(React)側
まず、Reactのチュートリアルで作成したindex.js
とindex.css
をreact/src/
にそれぞれ配置する。
└ react/
├ public/
│ └ index.html
└ src/
├ index.js <= ここ
└ index.css <= ここ
その際、index.js
の先頭に以下のコードを追加する。既にローカル環境で開発していればコードの追加は不要。コードは割愛。
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
次に、react/public/index.html
を作成する。
└ react/
├ public/
│ └ index.html <= ここ
└ src/
├ index.js
└ index.css
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>React Tutorial</title>
</head>
<body>
<div id="root"></div>
<script src="../src/index.js"></script>
</body>
</html>
こちらはReactのチュートリアルで作成したものではなく、Electronのクイックスタートで掲載されているコードを流用し、<script src="../src/index.js"></script>
を追加した。Parcelでトランスパイルする際は、このreact/public/index.html
がターゲットとなる。
メインプロセス側
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// ビルド後のindex.htmlを読み込む
win.loadFile('parceled/index.html')
//win.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
エントリーポイントとなるelectron/main.js
を作成。
├ electron/
│ ├ main.js <= ここ
│ └ preload.js
これもほとんどElectronのクイックスタートと変わらないが、win.loadFile('parceled/index.html')
として、ビルド後のHTMLファイルを読み込むように変更した。
electron/preload.js
も作成したが、今回はメインプロセスとレンダラープロセスで通信を行わないので、中身は空っぽ。
├ electron/ここ
│ ├ main.js
│ └ preload.js <= ここ今回は空
Parcelでビルド
parcel build --out-dir parceled --public-url ./ react/public/index.html --no-minify
electron-builderの出力先と被らないようにビルドしたファイルの出力先を変更し、--public-url ./
でindex.html
が読み込むJSファイルのパスを指定した。また、--no-minify
でビルド時のサイズ圧縮を無効にしている。最初は有効だったけれど、Parcelの依存パッケージであるcssnano
にエラーがでてやむなく無効化。ダウングレードすればいけるっぽいけど未検証。
electron-builderでビルド
package.jsonの編集
{
"name": "react_tutorial",
"version": "1.0.0",
"description": "",
"main": "electron/main.js",
"scripts": {
"electron": "electron .",
"build-win": "electron-builder --win --x64"
},
"author": "",
"license": "MIT",
"devDependencies": {
"electron": "^19.0.0",
"electron-builder": "^23.0.3",
"react": "^18.1.0",
"react-dom": "^18.1.0"
},
"build": {
"appId": "react.tutorial",
"win": {
"target": "portable"
}
}
}
package.json
にビルド用のコマンドと、build
セクションを追加した。今回はインストールする必要はないので、ポータブル版を設定。
ビルド
npm run build-win
しばらく待つとdist
にreact_tutorial 1.0.0.exe
が出力される。
実行
無事にElectron上でReactのチュートリアルが再現できた。
あとはウィンドウサイズを変更したり、メニューバー消したり好きにできる。
さいごに
Electron上でReactを使うのって結構めんどくさいけど、Parcelがないともっとめんどくさかったはず。Parcelは偉大。
参考文献