Electron を始める

# はじめに

Windows のデスクトップアプリを作るのに、自分は Electron も使っていて、使い始めてから随分になります。使い方を整理しておこうと思いました。

# Electron とは

Electron は、JavaScript、HTML、CSS によるデスクトップアプリケーションを構築するフレームワークです。 Electron は Chromium と Node.js をバイナリに組み込むことで、単一の JavaScript コードベースを維持しつつ、ネイテイブ開発経験無しでも Windows、macOS、Linux で動作するクロスプラットフォームアプリを作成できます。

[はじめに | Electron](https://www.electronjs.org/ja/docs/latest/)

![説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114460/82fc60ca-2c4e-20db-2909-715d390f4d5b.png)

いわゆる「OS のネイティブアプリ」は、OS 上で実行できるバイナリファイルで、OS の機能を呼出して動作します。開発環境や開発言語が OS ごとに用意され、その OS 用の実行ファイルが作成されます。同じソースコードのプログラムを異なる OS で動作できません。
これに対して、いわゆる「ウェブアプリ」は、HTML と JavaScript で書かれたプログラムが、ウェブブラウザに読込され実行されます。同じ動作するブラウザがあれば同じウェブアプリのプログラムが異なる OS で動作します。ウェブブラウザが呼出できない OS の機能は利用できません。
「Electron」を使ったアプリは、ウェブアプリ＋ウェブブラウザが実行ファイルになってネイティブアプリのように OS 上で動作します。さらに Node.js アプリを内包できて、ウェブブラウザで呼出できない OS の機能も呼出できるようになっています。ウェブブラウザおよび Node.js エンジンを OS ごとに切替して実行ファイルを作成することで、同じ HTML＋JavaScript のプログラムで異なる OS で動作するアプリを作成できます。ウェブブラウザおよび Node.js エンジンを内包するため、OS ネイティブアプリに比べて実行ファイルが大きくなってしまいます。
これを解消するために、Node.js の代わりに Rust や Go を使い、ブラウザ機能内蔵の代わりに OS が持つブラウザ機能を呼出する、Tauri や Wails が作られています。

# Electron を始める

* Electron 36.4

## 開発および実行できる環境

Electron は、以下の環境で開発できて、さらに作成したアプリが実行できます。

* Windows 10 以降 (x64 および ARM64)
* MacOS 11 以降 (x64 および ARM64)
* Linux (x64 および ARM64)

## 開発環境を準備する

以下の手順で開発環境を準備します。

[必要な環境 | Electron](https://www.electronjs.org/ja/docs/latest/tutorial/tutorial-prerequisites)

### Node.js 環境をインストールする

まず Node.js 環境をインストールします。

[Node.js — Node.js®をダウンロードする](https://nodejs.org/ja/download)

### Electron 開発環境をインストールする 

`npm install electron` を使って Electron 開発環境をインストールします。

Electron 開発環境は、開発機の Node.js 環境自体にインストールしてもいいのですが、後述するタイミングで個別のプロジェクトにインストールするのがいいようです。

## プロジェクトを新規作成する

プロジェクトを作成したいフォルダを作成します。そこに移動してコマンドを実行します。

```shell
npm init
```

アプリ名などを入力します。`package.json` が作成されます。

```json:package.json
{
    "name": "helloelectron",
    "version": "1.0.0",
    "description": "",
    "license": "ISC",
    "author": "Tiny Mouse",
    "type": "commonjs",
    "main": "main.js",
}
```

参考 [初めてのアプリのビルド | Electron](https://www.electronjs.org/ja/docs/latest/tutorial/tutorial-first-app)

## プロジェクトに必要なモジュールを加える

プロジェクトのフォルダに必要なモジュールを加えていきます。

参考 [最新版で学ぶElectron入門 - ウェブ技術でPCアプリを開発しよう - ICS MEDIA](https://ics.media/entry/7298/)

まず、`Electron` モジュールをインストールします。

```shell
npm install electron --save-dev
```

続いて、アプリの骨格になるファイルを追加していきます。

### main.js

エントリポイントになる `main.js` を用意します。

```js:main.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')

app.on('ready', () => {
    const win = new BrowserWindow({
        width: 800, height: 600,
    })

    win.loadFile(
        path.join(__dirname, "index.html")
    )
})

app.on('window-all-closed', () => {
    if (process.platform != 'darwin') {
        app.quit()
    }
})
```

アプリが起動するときの状態を指定できそうです。

### index.html

アプリのフロントエンドになる `index.html` を作成します。

```html:index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta
        http-equiv="Content-Security-Policy"
        content="default-src 'self'; script-src 'self'"
        />
        <meta
        http-equiv="X-Content-Security-Policy"
        content="default-src 'self'; script-src 'self'"
        />
        <title>Hello Electron!</title>
    </head>
    <body>
        <p>Hello Electron!👋</p>
    </body>
    <script src="./renderer.js"></script>
</html>
```

### renderer.js

`index.html` で読込される JavaScript ファイルを必要に応じて記述します。

```js:renderer.js
(空)
```

## アプリを開発モードで実行する

プロジェクトのフォルダに移動してコマンドを実行します。

```shell
./node_modules/.bin/electron . 
```

`Electron` 環境が起動して、`package.json` の設定に従って `main.js` のコードが実行されます。そのコードに従って `index.html` がロードされて画面に表示されます。

# VS Code で開発する

上記のコードをエディタで編集してコマンド実行すればアプリが作成できますが、コードの編集やデバッグは IDE（統合開発環境）を使いたいものです。

VS Code (Visual Studio Code) を使うことにします。

## VS Code をインストールする

VS Code をダウンロードしてインストールします。

[Download Visual Studio Code - Mac, Linux, Windows](https://code.visualstudio.com/download)

## 拡張機能をインストールする

Go アプリをデバッグするための拡張機能をインストールします。

[Visual Studio Code for Go 開発のインストールと構成 - Go on Azure | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/developer/go/configure-visual-studio-code)

## プロジェクトのフォルダを開く

作成したプロジェクトのフォルダを VS Code で開きます。

[VSCodeの基本～プロジェクトフォルダの設定方法について解説します！ | プログラミング入門ナビ by Proglus（プログラス）](https://blog.proglus.jp/4672/)

## launch.json を用意する

効率よくデバッグできるように VS Code のデバッグ構成 `launch.json` を用意します。

公式サイトで紹介されているものを使ってみます。[VS Code でデバッグする | Electron](https://www.electronjs.org/ja/docs/latest/tutorial/debugging-vscode)

```json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug Main Process",
            "type": "node",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
            "windows": {
                "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
                },
            "args" : ["."],
            "outputCapture": "std"
        }
    ]
}
```

これで、VS Code でアプリを実行できるようになります。
`main.js` はブレークポイントを設定したりステップ実行できます。
`renderer.js` はだめですね。↑

`renderer.js` のコードもブレークポイントを設定したりステップ実行できるようにしたいので、`launch.json` に追記します。
参考 [VSCodeでElectronのMainおよびRendererプロセス両方をデバッグ実行する方法 #VSCode - Qiita](https://qiita.com/gtk2k/items/059dadcdf692198e98d3)

公式サイトでも紹介されていました。[初めてのアプリのビルド | Electron](https://www.electronjs.org/ja/docs/latest/tutorial/tutorial-first-app)

```json:launch.json
{
    "version": "0.2.0",
    "compounds": [
        {
            "name": "Main + Renderer",
            "configurations": ["Main", "Renderer"],
            "stopAll": true
        }
    ],
    "configurations": [
        {
            "name": "Main",
            "type": "node",
            "request": "launch",
            "cwd": "${workspaceFolder}",
            "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
            "windows": {
                "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
            },
            "args": [".", "--remote-debugging-port=9222"],
            "outputCapture": "std",
            "console": "integratedTerminal",
            "presentation": {
                "hidden": true,
            }
        },
        {
            "name": "Renderer",
            "type": "chrome",
            "request": "attach",
            "webRoot": "${workspaceFolder}",
            "port": 9222,
            "presentation": {
                "hidden": true,
            }
        },
    ]
}
```

# 配布パッケージを作成する

作成した `Electron` アプリを配布するには、配布パッケージにしなくてはいけません。

[アプリケーションのパッケージ化 | Electron](https://www.electronjs.org/ja/docs/latest/tutorial/application-distribution)

公式サイトでは `Electron Forge` が紹介されています。
他に `Electron Packager` が使えるようです。
自分は `Electron Builder` を使っています。

[Electronで1からデスクトップアプリを作り、electron-builderを使ってビルド・リリースするまで #JavaScript - Qiita](https://qiita.com/saki-engineering/items/203892838e15b3dbd300)

### Electron Builder をインストールする

`Electron Builder` をインストールします。

```shell
npm install electron-builder --save-dev
```

### ソースコードをフォルダにまとめる

プロジェクトのフォルダにある `main.js` などのソースコードを `src` フォルダにまとめておきます。（しなくても構いません）

```
helloelectron (プロジェクトのフォルダ)
    package.json
    src
        main.js
        index.html
        renderer.js
    node_modules
```

### package.json に追記する

Electron Builder が参照する設定を `package.json` に追記します。

```json:package.json
    (前略)
    "devDependencies": {
        "electron": "^36.4.0",
        "electron-builder": "^26.0.12"
    },
    "scripts": {
        "build:win": "electron-builder --win",
        "build:mac": "electron-builder --mac",
    },
    "build": {
        "appId": "com.electron.hello",  // アプリID
        "productName": "Hello",         // アプリ名
        "win": {
            "target": "portable"
        },
        "mac": {
            "target": "dir"
        }
    }
}
```

プロジェクトのフォルダに移動してコマンドを実行します。

```shell
npm run build:win 
```

配布するための実行ファイルが、プロジェクトのフォルダ内の `dist` に作成されます。

```
helloelectron (プロジェクトのフォルダ)
    package.json
    src
    (中略)
    dist
        (中略)
        Hello 1.0.0.exe
```

`package.json` の `ProductNaem` と `version` で指定したファイル名になります。

### アイコンを変更する

アプリのアイコンを変更できます。

まず、画像ファイルを用意します。`ico` ファイルなど用意しなくても `png` など画像ファイルを用意すれば、Electron Builder が変換してくれるようです。

```
プロジェクトのフォルダ
    package.json
    src
    (中略)
    res
        icon
            app.png
```

`package.json` を修正します。

```json:package.json
        (前略)
        "win": {
            (中略)
            "icon": "res/icon/app.png"
        },
        "mac": {
            (中略)
            "icon": "res/icon/app.png"
        }
        (後略)
```

### インストーラを作成する

`Electron Builder` では、実行ファイルだけでなくインストーラを作成できます。`package.json` を修正します。

```json:package.json
        (前略)
        "win": {
            "target": "nsis"
        },
        "nsis": {
            "oneClick": false,                          // ワンクリックインストールを有効にするか
            "perMachine": false,                        // 全てのユーザにインストールするか、それともユーザーごとにインストールするか
            "allowToChangeInstallationDirectory": true, // インストール先ディレクトリの変更を許可するか
            "createDesktopShortcut": true,              // デスクトップにショートカットを作成するか
            "createStartMenuShortcut": true,            // スタートメニューにショートカットを作成するか
            "shortcutName": "Hello Electron App",       // ショートカット名
        },
        "mac": {
            "target": "dmg",
        },
        "dmg": {
            "title": "${productName} Installer",   // DMGファイルのタイトル
        }
    }
}
```