【Electron】HTML/CSS/JavaScript でデスクトップアプリを作った【インストールから exe 化まで】

# 2023/02/17 追記
今も見てくださる方がちらほらいらっしゃるみたいです。ありがとうございます。
ちょっと情報が古いかもなので、他の記事を参考にされた方がよいかもしれません・・・

# HTML/CSS/JavaScript でデスクトップアプリを作りたかった
こんにちは、ndj です。
今までデスクトップアプリ作成には `Python` の `tkinter` ライブラリしか使用したことがなかったのですが、
ボタンやラベルの配置など結構独特で難しいなあという印象がありました。
今回は HTML/CSS/JavaScript などのいわゆる Web 関連の技術でデスクトップアプリケーションを作成することができる `Electron` という `JavaScript` のフレームワークを使用して、超簡易的なアプリケーションを作成してみました。

※本記事内の `Electron` および関連パッケージのインストール方法、パッケージ化などのセクションについては `Windows` 向けです。

## 使用環境

- OS: Windows10 Pro 64bit
- Node.js: v10.18.0
- npm: 6.13.4
- Electron: v10.1.5
- Electron Builder: v22.9.1

## Electron とは
>Electronは、GitHubが開発したオープンソースのソフトウェアフレームワークである。
ChromiumとNode.jsを使っており、HTML、CSS、JavaScriptのようなWeb技術で、macOS、Windows、Linuxに対応したデスクトップアプリケーションをつくることができる。
Wikipedia [Electron(ソフトウェア)](https://ja.wikipedia.org/wiki/Electron_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2))より引用

上記のように、`Electron` では、HTML/CSS/JavaScript のような Web 技術を用いてクロスプラットフォームのデスクトップアプリケーションを作成することができます。
**Visual Studio Code**、**Atom**、**Slack** などが `Electron` を用いて開発されているそうです。

他のソフトウェアに関しては[こちら](https://www.electronjs.org/apps)から探すことができます(`Electron` 公式ページのアプリ一覧にとびます)。

`Electron` 自体の技術的なことに関してはこちらの記事がとても分かりやすかったです。

https://qiita.com/umamichi/items/6ce4f46c1458e89c4cfc

https://www.buildinsider.net/enterprise/electron


## Electron をインストールする
### まずは Node.js をインストールする
`Electron` を使用するためには `Node.js` がインストールされている必要があります。
`Node.js` がインストールされているかどうかを確認するにはコマンドプロンプトで以下のコマンドを実行してバージョン情報が表示されていればOKです。

```
node --version
> v10.18.0 ← これが表示されていればOK
```

`Node.js` のインストール方法に関しては以下の記事がとても参考になりました。

https://qiita.com/sefoo0104/items/0653c935ea4a4db9dc2b

### npm がインストールされている確認する
おそらく、`Node.js` をインストールした際に、`npm` というパッケージ管理ツールも導入することができていると思います。

```
npm --version
> 6.13.4 ← これが表示されていればOK
```
### プロジェクトを作成する
まずは、`npm init` して、プロジェクトを作成します。
今回は `ElectronTest` というプロジェクトを作成しました。

```
mkdir ElectronTest
cd ElectronTest
npm init
```
`npm init` をしたときにコマンドプロンプト上で色々聞かれるかもしれませんが、これは `package.json` の内容をどうするか聞かれています。
`package.json` はあとで編集できますので、とりあえず Enter 連打でも大丈夫です。

該当のプロジェクトディレクトリに `package.json` が作成されていたら、とりあえずここはOKです。

```
dir
ElectronTest>dir
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は XXXX-XXXX です

ElectronTest のディレクトリ

2020/11/09  02:02    <DIR>          .
2020/11/09  02:02    <DIR>          ..
2020/11/09  02:00               208 package.json ←これ
               4 個のファイル                 208 バイト
               2 個のディレクトリ  39,629,983,744 バイトの空き領域
```

### Electron をインストールする
いよいよ `Electron` がインストールできます。
プロジェクト直下のディレクトリで以下のコマンドを実行します。

```
~ElectronTest> npm i -D electron
```
他にも、`node-modules` ディレクトリや `package-lock.json` ファイルなどが作成されるので、合わせて確認してもらえれば。

### ！注意
今回はプロジェクト内にて、`Electron` をインストールしています。
[こちらの記事](https://qiita.com/TigRig/items/64d55b5fc5483b01c3b5)によると、**グローバルインストールをした場合は、Electron がアップデートされた場合に、プロジェクトによっては動かなくなってしまう**ことがあるため、ローカルインストールが推奨されているみたいです。

なにはともあれ、`Electron` がインストールされるのを待ちましょう。
私の環境に限っての話かもしれませんが、インストールに結構時間がかかったのでお茶でも飲んで待ってるといいかもです。
インストールが完了したら、以下のコマンドを実行して `Electron` がインストールされている確認します。

```
~ElectronTest> electron --version
> v10.1.5 ← これが表示されていればOK
```

## Electron を実行する

### 表示する HTML を書いていく
アプリを起動したときに表示される `HTML` を書いていきます。
とりあえずテストとして、以下のようにシンプルな `HTML` にしておきます。

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Hello Electron!</h1>
</body>
</html>
```

ご覧の通り、いたってノーマルな `HTML` ですので、ブラウザで確認することもできますね。

### Electron アプリのメインプロセスを書いていく
アプリケーションのメインプロセスとなる、`main.js` を書いていきましょう。
ちなみにメインプロセスのファイル名は `package.json` の `main` にて定義されていますので、こちらも変更しておきましょう。

```
{
  "name": "electrontest",
  "version": "1.0.0",
  "description": "",
  "main": "main.js", ←デフォルトだと index.js になっているのでここを変更しておきます。
  (以下略)
}
```

ここから `main.js` を書いていきます。

```main.js
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;
app.on('ready', () => {
    // mainWindow を作成
    mainWindow = new BrowserWindow({width: 400, height: 400});

    // html を指定
    let path = 'file://' + __dirname + '/index.html';
    mainWindow.loadURL(path);

    // developper tool を開く
    // mainWindow.webContents.openDevTools();

    mainWindow.on('closed', function() {
        mainWindow = null;
    });
});
```

上記を保存したら、いよいよプログラムを実行していきます。

### いざ実行
コマンドプロンプトで以下のコマンドを実行することで `Electron` アプリケーションを実行することができます。

```
~ElectronTest> electron main.js
```

![20201109_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485313/d72f07bc-d2a9-c998-bac1-38809c23a633.png)

実行することができました！

### 色々 index.html をカスタマイズしていく
今回は簡単な時計アプリを作りたいので、そんな感じで最初に表示される `index.html` をカスタマイズしていきます。
`CSS` や `JavaScript` も使っていきたいと思います。
デザインに関しては、[こちら](https://goworkship.com/magazine/clock-timer-code-snippets/)の記事を参考にさせていただきました。

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>scr</title>
    <link rel="stylesheet" href="static/css/style.css">
    <script src="static/js/watch.js"></script>
</head>
<body>
    <div class="clock-wrapper">
        <p id="clock">00:00:00</p>
    </div>
</body>
</html>
```
```style.css
body {
    background-color: #000000;
}
#clock {
    font-family: "Arial";
    text-align: center;
    font-size: 400%;
    text-shadow: 0 0 20px #aaffaa, 0 0 20px rgba(10, 175, 230, 0);
    color: #e1ffda;
    height: 20%;
}
.clock-wrapper {
    text-align: center;
}
```
```watch.js
// 日付を取得し、時間を更新する
function setClock(){
    let elClock = document.getElementById("clock");
    
    let nowDate = new Date();
    let hour = zeroPadding(nowDate.getHours(), 2);
    let minutes = zeroPadding(nowDate.getMinutes(), 2);
    let seconds = zeroPadding(nowDate.getSeconds(), 2);

    elClock.innerHTML = hour + ":" + minutes + ":" + seconds;
}

// 数値が一桁の場合、0埋めをおこなう
function zeroPadding(targetNum, paddingNum) {
    const ZERO = "0";
    let joinedZero = ZERO.repeat(paddingNum) + String(targetNum);
    return joinedZero.slice(-paddingNum);
}

// 一秒間隔で時間を更新する処理を繰り返す
let timer = setInterval("setClock()", 1000);
```

```
~ElectronTest> electron main.js
```

![20201109_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485313/a3073c27-92a6-94ab-c20f-5426efa9ce26.png)

いけました！！！
毎秒時間が更新されます。
超簡易的ですが、今回作成したこいつを `.exe`化していきたいと思います。

## パッケージ化に必要な Electron Builder をインストールする
本記事では、`Electron` で作成したアプリを `exe`化までしたいので、`Electron` で作成したアプリケーションを `exe`化するのに必要な`Electron Builder` をインストールします。
なお、「electron exe化」みたいなキーワードで色々調べると「`Electron Packager`」というツールがめちゃくちゃ出てくると思いますが、現在では上記の `Electron Builder` が主流っぽいです(詳細については調べておきたいと思います)。

インストール方法については[こちら](https://qiita.com/zaburo/items/828051fc7dabb258f0de)や[こちら](https://qiita.com/saki-engineering/items/203892838e15b3dbd300)の記事が非常に参考になりました。

```
~ElectronTest> npm i -D electron-builder
```

`package.json` に以下の記述が足されていればOKです。

```
(中略)
"devDependencies": {
    "electron-builder": "^22.9.1"
}
```

## いよいよ exe化する

### build-win を記述する
以下のファイルをプロジェクトディレクトリ直下に作成します。

```build-win
const builder = require('electron-builder');

builder.build({
    config: {
        'appId': 'electorn-test',
        'win':{
            'target': {
                'target': 'zip',
                'arch': [
                    'x64',
                    'ia32',
                ]
            }
        }
    }
});
```

### ビルド実行
プロジェクトディレクトリで以下のコマンドを実行します。

```
~ElectronTest> node build-win
```

build にちょっと時間がかかるのでまたお茶でも飲んで待ちましょう。
build が完了したら、プロジェクトディレクトリに `dist` ディレクトリが作成されていると思います。
その中に `win-unpacked` ディレクトリに、 `.exe`化されたファイルがあるので、実行してみてください。

## インストーラーについて
`win-unpacked` の中に関連ファイルが沢山あってアレなのでインストールできる形にしたいのですが、長くなってしまった＆ちょっと時間かかかりそう。。。
なのでインストーラーについては後日また記事を書いていきたいと考えています。

## 最後に
Web 技術を用いて、デスクトップアプリケーションを作成するのはある意味新鮮な感じで楽しかったです。
業務に活かしていけるレベルではまだまだありませんが、活用できるところは活用していきたいなと思います。
ここまで読んでくださり、ありがとうございました！！

## 参考
### Electron の技術について

https://www.electronjs.org/apps

https://ja.wikipedia.org/wiki/Electron_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2)

https://qiita.com/umamichi/items/6ce4f46c1458e89c4cfc

https://www.buildinsider.net/enterprise/electron

### Node.js および関連パッケージのインストールについて

https://qiita.com/sefoo0104/items/0653c935ea4a4db9dc2b

https://qiita.com/TigRig/items/64d55b5fc5483b01c3b5

https://qiita.com/zaburo/items/828051fc7dabb258f0de

https://qiita.com/saki-engineering/items/203892838e15b3dbd300

### デザインについて

https://goworkship.com/magazine/clock-timer-code-snippets/

参考にさせてくださった皆様、ありがとうございました。
これからも巨人の肩の上に乗り続けます。