electron-webpackでTypescript+Reactプロジェクトを作成する

# tl;dr
electron-webpackでTypescript+Reactのelectronプロジェクト雛形を作りました。
多分すぐ陳腐化するので`2020/08/26`ブランチを切っています。
https://github.com/thalathalaylah/electron-webpack-ts-react-template/tree/2020/08/26

# これはなに
electron-webpackってやつを使うとelectronのプロジェクトが簡単に作れるらしいぜ。
ということでTypescript+Reactのものを作ろうとしたら所々ハマったのでまとめます。

もしくは「[create-react-appとtypescriptでelectronをやる](https://qiita.com/thalathalaylah/items/40188de9fd2932d5d2ee)」のリファイン。

# 環境
おおまかなものです。
細かくはリポジトリの[package.json](https://github.com/thalathalaylah/electron-webpack-ts-react-template/blob/2020/08/26/package.json)を見てください。

|対象|version|
|:---|---:|
|Mac|HighSierra 10.13.6|
|yarn|1.15.2|
|electron|10.0.0|
|electron-webpack|2.8.2|

# やったこと
commitのリンクを見出しにしていくので、細かい差分はそちらで確認してください。

## [electron-webpack導入](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/ac5754b50896cae951af4f5d0fe067055f0c6cee)
```bash:console
echo node_modules > .gitignore
yarn add electron-webpack electron webpack --dev
yarn add source-map-support
```
`.gitignore`にnode_moduleを追加
あとは https://webpack.electron.build/development の通りに`electron-webpack`, `electron`, `webpack`, `source-map-support`を導入する。 
`source-map-support`は`--dev`をつけずにaddしないと、パッケージ化する際に失敗する。

## [electron-webpack-quick-startのページを表示するアプリが起動する](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/6923710e5fe03becb70c4279a9a5cb73626b21da)
```bash:console
echo dist >> .gitignore
```
`.gitignore`にdistを追加。

```package.json
{
  "scripts": {
    "dev": "electron-webpack dev"
  },
  ......
}
```
`package.json`にdevコマンドを追加。

[electron-webpack-quick-startの2020/08/04時点最新](https://github.com/electron-userland/electron-webpack-quick-start/tree/d3a683e19f6bec80542011a99ecf91ad4eda01e0)の`src/main/index.js` と `src/renderer/index.js` を同様のディレクトリ構造でコピー。
これらの作業もhttps://webpack.electron.build/development の通り。

この時点で`yarn dev`コマンドを実行すると、electronアプリが起動する。

## [Typescript導入](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/7e9f179138ffb818774ce9e28a76f1b2b6eb07d3)
```bash:console
yarn add typescript electron-webpack-ts --dev
```
`typescript`と`electron-webpack-ts`を導入。

```tsconfig.json
{
  "extends": "./node_modules/electron-webpack/tsconfig-base.json"
}
```
tsconfig.jsonを作成し、electron-webpackからextendsする設定を記述。
ここまでは https://webpack.electron.build/add-ons#typescript の通り。

```bash:console
yarn add @types/node@12 --dev
```
electron10系はnode12上で動くため、型情報は`@types/node@12`を利用する。
nodeの13系以上ではエラーが発生した。

その後、`src/main/index.js`を`src/main/index.ts`にリネーム。
10行目の`let mainWindow`で型が無いことをによりエラーが発生するため、 `let mainWindow: BrowserWindow | null` としておく。

この時点で`yarn dev`コマンドを実行すると、再度electronアプリが起動できる状態になっている。
前コミットとの差はMainProcessのコードがTypescriptで動いていること。

## [React導入](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/39ea8ed47ee4203d8c142b0101826fab0a580e88)
```bash:console
yarn add @babel/preset-react --dev
```
```tsconfig.json
{
......
  "compilerOptions": { "jsx": "react" }
}
```
https://webpack.electron.build/add-ons#react-jsx の通り、jsxのコンパイルに必要なものを入れる。

```bash:console
yarn add react react-dom @types/react @types/react-dom --dev
```
React関連の依存を追加する。

その後、`src/renderer/index.js`を`src/renderer/index.tsx`にリネームし、Reactの表示用コードを書く。
ここで、https://webpack.electron.build/development#use-of-html-webpack-plugin にある通り、ReactDOM.renderで最初に指定するcontainerは`id=app`のelementを取得する必要がある。
https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/39ea8ed47ee4203d8c142b0101826fab0a580e88#diff-6991cac75f36bcce6c7cdbad5540d934R5

## [ReactDevTools導入](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/fd4e330815f1288baf34b381a2dfc9d3a500f8fe)
```bash:console
yarn add electron-devtools-installer @types/electron-devtools-installer --dev
```
> You may also try electron-devtools-installer

と、 https://github.com/electron/electron/blob/v10.0.0/docs/tutorial/devtools-extension.md にある通り、electron-devtools-installerを導入。
https://www.npmjs.com/package/electron-devtools-installer の通りに`src/main/index.ts`でReactDevToolsを読み込むようにする。

## [アプリをビルドできる](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/625bee09c8e02c480874788dc12b5f1839ad059c)
```bash:console
yarn add electron-builder --dev
```
`electron-builder`を導入。

```diff:package.json
 {
   "scripts" {
     "dev": "electron-webpack dev",
+    "build": "electron-webpack && electron-builder --mac --x64"
   }
+  "name": "electron-webpack-ts-react-template",
+  "version": "0.0.1",
   ......
 }
```
1. buildスクリプトを追加。今回はmac上なので`--mac`だが、OSによって適宜変える。
2. nameはアプリの名前。
3. versionは適宜つける。

```diff:src/main/index.ts
-import installExtension, {
-  REACT_DEVELOPER_TOOLS,
-} from 'electron-devtools-installer';

 const isDevelopment = process.env.NODE_ENV !== 'production';

......
  
   if (isDevelopment) {
-    installExtension(REACT_DEVELOPER_TOOLS)
-      .then((name) => console.log(`Added Extension: ${name}`))
-      .catch((err) => console.log('An error occurred: ', err));
+    import('electron-devtools-installer').then((module) => {
+      module
+        .default(module.REACT_DEVELOPER_TOOLS)
+        .then((name) => console.log(`Added Extension: ${name}`))
+        .catch((err) => console.log('An error occurred: ', err));
+    });
     window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`);
   } else {
......
```
electron-devtools-installerはアプリ化した際に読み込めないようなので、開発時にのみ動的にimportするように変更する。
`package.json`で`electron-devtools-installer`をdevDependencyからdependencyに移動することでも対処できる。
しかし、開発用の機能なのでdependencyに移動するのも良くないと考え、動的importを選択した。

## [ボタン追加](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/51a534ff84c0c392e108fa28874c223a75a17473)
クリック可能なボタンを作成し、クリック時にconsoleに文字列を表示する。

## [nodeの力を使ってみる](https://github.com/thalathalaylah/electron-webpack-ts-react-template/commit/1d18f0437edcee41c0956ed290b1b95932e8a859)
Button.tsxでchildProcessをimportし、lsコマンドを実行、dev toolのconsoleに表示する。
これでローカルのリソースにアクセスできていることが確認できる。

# そういうわけで
electron-webpackを使ってプロジェクト雛形を作ってみたが、つまづきが多かったのでまとめた。
create-react-appから頑張るよりは良い感じなのではないかと思う。