【初心者向け】Electron Forgeでお手軽Electronアプリ開発（環境構築、Typescript+React導入、自動更新）

# はじめに
この記事では`electron-forge`を使って`Typescript`+`React`の`electron`アプリを構築したいと思います。
開発環境の構築方法から作成したアプリの公開、自動更新までを紹介します。



# electronとは
JavaScript, HTML, CSSで構築できるクロスプラットフォームなデスクトップアプリ開発のフレームワークです。
有名なElectron 製アプリとしては「Vistual Studio Code」や「Slack」などがあります。

<img width="100px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/edfe0b0e-e7ae-079d-865a-4fa5aab9648c.png" />　<img width="100px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/5988b726-f922-4cdf-12b8-49eec73a8bcd.png" />　<img width="100px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/f4322ca2-dd4b-14bf-71be-dd353b3e0021.png" />

# electron 開発環境
electron アプリをパッケージング（コードをアプリケーション化する）するツールとしては以下の二つが広く使われているようです。

- [electron-forge](https://www.electronforge.io/)
- [electron-builder](https://www.electron.build/)

`electron-builder`はパッケージツールで`electron-forge`はパッケージツール＋ボイラーテンプレートという認識で問題なさそうです。

`electron-forge`はボイラーテンプレートがあるので、開発環境を簡単に構築できます。`electron`+`Typescript`+`React`などで検索すると`webpack.config.js`や`tsconfig.json`をかなりいじる構築方法が出てきますが、`electron-forge`を使うとそのあたりの面倒を見てくれます。

今回は、`Typescript`+`React`という構成で開発したいので、`electron-forge`を使ってelectronアプリを構築します。

# 使用環境
- Windows10 64 bit
- electron 14.0.1
- electron-forge 6.0.0-beta.57
- yarn 1.22.5

<font color="Red">Macを使用する場合は、自動更新にアプリ署名が必要です。</font>

# 環境構築

`electron-forge`を使って`electorn`アプリの開発環境を構築します。
以下の`electron-forge`の公式ドキュメントを参考に（TypeScript + Webpack）の環境を構築します。

https://www.electronforge.io/templates/typescript-+-webpack-template

最初に以下のコードを実行します。（`yarn`がない場合はインストールするか`npm`で実行してください。）

```shell
yarn create electron-app my-new-app --template=typescript-webpack
```

上記のコマンドを実行すると`my-new-app`というフォルダが作成されるので以下のコマンドでフォルダの中に移動してアプリを起動します。

```shell
cd my-new-app
yarn start
```

以下のように表示されれば成功です。

![electron-start.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/87ff1111-e4d4-a2ca-05eb-dc904683ad2d.png)

次に、`React`を導入します。
以下のドキュメントを参考にします。

https://www.electronforge.io/guides/framework-integration/react-with-typescript

必要なライブラリをインストールします。

```shell
yarn add react react-dom
yarn add --dev @types/react @types/react-dom
```

ライブラリをインストール後、`tsconfig.json`、`src/app.tsx`、`src/renderer.ts`を編集します。

```diff_json:tsconfig.json
{
  "compilerOptions": {
    "allowJs": true,
    "module": "commonjs",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "noImplicitAny": true,
    "sourceMap": true,
    "baseUrl": ".",
    "outDir": "dist",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "paths": {
      "*": ["node_modules/*"]
-   }
+   },
+   "jsx": "react"
  },
  "include": [
    "src/**/*"
  ]
}

```


```tsx:src/app.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';

function render() {
  ReactDOM.render(<h2>Hello from React!</h2>, document.body);
}

render();
```

```ts:src/renderer.ts
// ファイルの末尾に追加
import './app';
```

`yarn start`を実行して以下のような画面が出れば成功です。
これで`Typescript`+`React`の開発環境が整いました！簡単ですね！

![react.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/7d5d9059-2506-1250-52f8-7e846fc0fa85.png)



# 自動更新の設定
自動更新の導入は以下のドキュメントを参考にします。

https://www.electronforge.io/config/publishers

今回はgithubのrelease機能を使って実装しようと思います。
他にも`AWS S3`や自前のサーバーで更新することも可能です。

自動更新のために必要な手順は以下のとおりです。


1. githubの設定
2. 自動更新のコードを追加
3. githubで公開
4. パッケージのアップデート

順番に説明していきます。

## githubの設定

最初にgithubのリポジトリを作成してコードをpushしてください。
githubのリポジトリはprivateではなくpublicで作成する必要があります。

githubのユーザー名と作成したリポジトリ名は後で使用します。

次に、`electron-forge publish`コマンド（公開用のコマンド）を実行するために必要なgithubのアクセストークンを作成します。

githubアカウントの設定画面から`Developer settings`を選択します。

![setting.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/ee4deaa5-889b-0a24-ac9f-e30a5ba7b386.png)

`Personal acess tokens`の画面で`Generate new token`を選択します。

![tokens.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/c8149806-9662-d528-f9a4-7f3b163ea0a4.png)

以下のような画面が表示されるので、`Note`に任意の名前を入力し、`write:packages`を選択して`Generate token`をクリックします。

![screencapture-github-settings-tokens-new-2021-09-19-23_35_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/23562b18-2934-9d6e-1ce1-90c9c7e455e6.png)

トークンが作成されるので、赤枠で囲んだアイコンをクリックしてコピーしておいてください。
作成したトークンは公開時に使用します。

![screencapture-github-settings-tokens-2021-09-19-23_35_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/9dbb9c3d-90ee-f2cb-0b4d-53814f88010f.png)

以上でgithubの設定は完了です。
次は自動更新のコードを追加します。

## 自動更新のコードを追加

`electron`の自動更新にはいくつか方法がありますが、今回は`electron`公式の[auto-updater](https://www.electronjs.org/docs/api/auto-updater)を使います。

`src/index.ts`と`src/app.tsx`を以下のように変更します。
`src/app.tsx`はアップデート前とアップデート後がわかりやすいようにするために変更しています。


```ts:src/index.ts
import { app, BrowserWindow, autoUpdater, dialog } from 'electron';

// ファイルの末尾に追加
const server = 'https://update.electronjs.org'
const feed = `${server}/OWNER/REPO/${process.platform}-${process.arch}/${app.getVersion()}`

if (app.isPackaged) { // パッケージされている（ローカル実行ではない）
  autoUpdater.setFeedURL({
    url: feed,
  });
  autoUpdater.checkForUpdates(); // アップデートを確認する

  // アップデートのダウンロードが完了したとき
  autoUpdater.on("update-downloaded", async () => {
    const returnValue = await dialog.showMessageBox({
      message: "アップデートあり",
      detail: "再起動してインストールできます。",
      buttons: ["再起動", "後で"],
    });
    if (returnValue.response === 0) {
      autoUpdater.quitAndInstall();  // アプリを終了してインストール
    }
  });

  // アップデートがあるとき
  autoUpdater.on("update-available", () => {
    dialog.showMessageBox({
      message: "アップデートがあります",
      buttons: ["OK"],
    });
  });

  // アップデートがないとき
  autoUpdater.on("update-not-available", () => {
    dialog.showMessageBox({
      message: "アップデートはありません",
      buttons: ["OK"],
    });
  });

  // エラーが発生したとき
  autoUpdater.on("error", () => {
    dialog.showMessageBox({
      message: "アップデートエラーが起きました",
      buttons: ["OK"],
    });
  });
}
```

```tsx:src/app.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";

function render() {
  ReactDOM.render(
    <div>
      <h1>v1.0.0</h1>
      <h2>Hello from React!</h2>
    </div>,
    document.body
  );
}

render();

```

`src/index.ts`の`feed`のURLはアップデート確認のために接続しに行くためのURLを記載します。
`OWNER`はgithubのユーザー名、`REPO`はgithubのリポジトリ名に変更してください。

`https://update.electronjs.org`というのは`electron`が公式で提供している自動更新のためのサーバです。
以下の条件を満たす場合に使用できます。

- macOSまたはWindowsで動作するアプリである。
- アプリはGitHubのパブリックなリポジトリである。
- ビルド成果物は、GitHub Releases で提供する。
- ビルド成果物はコード署名されている。（macOS）

`https://update.electronjs.org`のgithubリポジトリは以下のURLです。

https://github.com/electron/update.electronjs.org

以上で、自動更新のためのコードは追加できたので、次は作成したアプリを公開します。

## githubで公開

公開するための`electron-forge`の設定とgithubへの公開方法です。

`electron-forge`の設定はデフォルトでは`package.json`に記載されていますが、ファイルを分けたほうが管理しやすいので、`forge.config.js`に移動します。

`package.json`の`config` を削除して、`forge`の中身を`forge.config.js`にコピーします。

```diff_json:package.json
{
  ...
- "config": {
-   "forge": {
-     ...
-   },
- },
  ...
}
```

```js:forge.config.js
module.exports = {
  makers: [
    {
      name: "@electron-forge/maker-squirrel",
      config: {
        name: "electron_publish",
      },
    },
    {
      name: "@electron-forge/maker-zip",
      platforms: ["darwin"],
    },
    {
      name: "@electron-forge/maker-deb",
      config: {},
    },
    {
      name: "@electron-forge/maker-rpm",
      config: {},
    },
  ],
  plugins: [
    [
      "@electron-forge/plugin-webpack",
      {
        mainConfig: "./webpack.main.config.js",
        renderer: {
          config: "./webpack.renderer.config.js",
          entryPoints: [
            {
              html: "./src/index.html",
              js: "./src/renderer.ts",
              name: "main_window",
            },
          ],
        },
      },
    ],
  ],
};
```

次に、`forge.config.js`に公開用の設定を追加します。

```diff_jsx:forge.config.js
module.exports = {
  makers: [
    {
      name: "@electron-forge/maker-squirrel",
      config: {
        name: "electron_publish",
      },
    },
    {
      name: "@electron-forge/maker-zip",
      platforms: ["darwin"],
    },
    {
      name: "@electron-forge/maker-deb",
      config: {},
    },
    {
      name: "@electron-forge/maker-rpm",
      config: {},
    },
  ],
  plugins: [
    [
      "@electron-forge/plugin-webpack",
      {
        mainConfig: "./webpack.main.config.js",
        renderer: {
          config: "./webpack.renderer.config.js",
          entryPoints: [
            {
              html: "./src/index.html",
              js: "./src/renderer.ts",
              name: "main_window",
            },
          ],
        },
      },
    ],
  ],
+ publishers: [
+   {
+     name: "@electron-forge/publisher-github",
+     platforms: ["win32"],
+     config: {
+       repository: {
+         owner: "OWNER",
+         name: "REPO",
+       },
+     },
+   },
+ ],
};
```

`platforms`はwindows用の設定です。macOSの場合は`darwin`、linuxの場合は`linux`を指定してください。
`OWNER`にはgithubのユーザー名、`REPO`にはリポジトリ名を指定してください。

以上で設定は完了したので、以下のコマンドを実行してください。
コマンド実行時にはgithubのアクセストークンが必要なので、環境変数に設定します。


```powershell:windowsの場合
$Env:GITHUB_TOKEN = "xxxx"
yarn electron-forge publish
```

```powershell:windows以外
GITHUB_TOKEN=xxxx
yarn electron-forge publish
```

コマンドの実行が完了するとDraft状態のReleasesが作成されます。
githubのReleasesに移動します。

![github.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/2fbc78c0-bda2-62a6-efb3-4405dc70f693.png)

Releasesページに移動するとDraft状態のものが作成されているので、`Publish release`を選択してリリースします。

![release.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/8f4fa908-05e8-7b3f-9dee-c07df3a62c76.png)

![screencapture-github-allJokin-electron-publish-releases-edit-untagged-955fe7fdf69eea961214-2021-09-18-22_17_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/f0ecc860-a02b-b5d2-dca5-54086cb21dcf.png)

releaseが完了するとv1.0.0が追加されていると思います。
次は新しいバージョンをリリースしてアップデートします。

## パッケージのアップデート

パッケージのアップデートは`package.json`の`version`を更新して`yarn electron-forge publish`を実行するだけです。
アップデートできたことがわかりやすいように`src/app.tsx`も変更します。

```diff_json:package.json
- "version": "1.0.0",
+ "version": "1.0.1",
```

```diff_tsx:src/app.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";

function render() {
  ReactDOM.render(
    <div>
-     <h1>v1.0.0</h1>
+     <h1>v1.0.1</h1>
      <h2>Hello from React!</h2>
    </div>,
    document.body
  );
}

render();
```

ファイルが更新できたら以下のコマンドを実行します。

```
yarn electron-forge publish
```

コマンドを実行したら先程と同じようにDraft状態のreleaseを公開しておきます。

v1.0.1を公開した状態でv1.0.0をインストールします。
インストールはreleseされている`Setup.exe`を実行するとできます。

![v100.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/dfbf75bd-d9d3-f18e-b088-e746629aaf2a.png)

v1.0.0を起動します。画面上でも`v1.0.0`と表示されています。

しばらくすると`アップデートがあります`というダイアログが表示されます。
アップデートは自動的にバックグラウンドでダウンロードされます。

![updateav.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/a8734937-c3b3-43ef-dc5b-0742d8e4a2e5.png)

ダウンロードが完了すると以下のようなダイアログが表示され、`再起動`をクリックするとアプリが終了して再起動されます。

![updatedone.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/d7b4a538-fcfe-bdee-60d8-086dcc226986.png)

再起動するとアップデートが完了します。
ダイアログで`アップデートはありません`と表示されて画面上のバージョンも`v1.0.1`に変わっています。

![updated.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600358/6e348505-c228-0cfd-8eba-8e6b8d0a7410.png)

以上でアップデートが完了しました！
新しいバージョンを公開すると自動で確認してインストールしてくれるのでとても便利です！

# まとめ

この記事では`electron-forge`を使った環境構築から自動更新までを紹介しました。
設定が面倒くさそうと思って`electron`開発を躊躇していた方はぜひ試してみてください！

なにかのお役に立てれば幸いです！