ReactのチュートリアルをElectronで動かす

# はじめに
「チュートリアル：Reactの導入」を一通り終えたとき、完成したコードをElectronで動かしたくなった。そこで、Parcelを使ってシンプルに構成してみる。`webpack.config.js`は書きたくない。:angry:

https://ja.reactjs.org/tutorial/tutorial.html

# 完成品
ビルドはしていない。
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`に実行ファイル形式で出力するイメージ。

# パッケージのインストール
```Shell
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`の先頭に以下のコードを追加する。既にローカル環境で開発していればコードの追加は不要。コードは割愛。
```javascript
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
```

```index.html
<!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`がターゲットとなる。

https://www.electronjs.org/ja/docs/latest/tutorial/quick-start


# メインプロセス側
```main.js
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 <= ここ今回は空
```

https://www.electronjs.org/ja/docs/latest/tutorial/context-isolation

# Parcelでビルド
```Shell
parcel build --out-dir parceled --public-url ./ react/public/index.html --no-minify
```
electron-builderの出力先と被らないようにビルドしたファイルの出力先を変更し、`--public-url ./`で`index.html`が読み込むJSファイルのパスを指定した。また、`--no-minify`でビルド時のサイズ圧縮を無効にしている。最初は有効だったけれど、Parcelの依存パッケージである`cssnano`にエラーがでてやむなく無効化。ダウングレードすればいけるっぽいけど未検証。

https://stackoverflow.com/questions/67951491/parcel-build-is-failing-bundle-scssundefinedundefined-plugin-is-not-a-functi


# electron-builderでビルド
### package.jsonの編集
```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`セクションを追加した。今回はインストールする必要はないので、ポータブル版を設定。

### ビルド

```Shell
npm run build-win
```
しばらく待つと`dist`に`react_tutorial 1.0.0.exe`が出力される。

https://www.electron.build/

# 実行
出力された実行ファイルをたたいてみると、、、
<img width="70%" alt="electron" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528323/3a84b25a-1835-c5a0-b691-eecdd5c2cfcb.png">

無事にElectron上でReactのチュートリアルが再現できた。
あとはウィンドウサイズを変更したり、メニューバー消したり好きにできる。

# さいごに
Electron上でReactを使うのって結構めんどくさいけど、Parcelがないともっとめんどくさかったはず。Parcelは偉大。

# 参考文献

https://qiita.com/eihigh/items/0aaf064014c5b1e72282