Electron備忘録(for Windows)

# 初めに
NodeJS+HTML+CSSでアプリを作る，Electronの備忘録です．
アプリ作成中の詰まったポイントと，その解決策を記録します．
**※この記事は，私の体験に基づいた解決策を記載しています．
公式ドキュメントの見落としや仕様の勘違いによる，間違えた箇所や効率の悪い書き方があると予想されます．
使用する前に公式のドキュメントや他の方のQ&Aを参照し，正確な情報を得ることをお勧めします．**
## 実行環境
Windows
Electron 22.0.0~


# Main⇔Rendererの通信
Electron バージョン14でremoteモジュールが削除されて以来，レンダラープロセスでメインプロセスの関数をそのまま使うことは非推奨にんった．
preloadを介してメイン⇔レンダラーのやり取りを行う必要がある．
## 返り値のない送受信
メインからレンダラーへ，あるいはレンダラーからメインへ，メッセージを送るのみ．
返り値はなく，await,async等で待つことはできない．

|通信の方向 |main.js|preload.js|備考|
|-----|-----|-----|--------|
|preload→main|`ipcMain.on`|`ipcRenderer.send`|
|main→preload|`win.webContents.send`|`ipcRenderer.on`|`win`は現在の`BrouserWindow`|

## 返り値のある送受信
非同期で実行されるものの，返り値がある．
await/asyncで待つことが可能．
主にメインプロセスの関数をレンダラープロセスで使うために用いられる．
|通信の方向 |main.js|preload.js|備考|
|-----|-----|-----|--------|
|preload→main→preload|`ipcMain.handle`|`ipcRenderer.invoke`|`ipcMain.handle`内に記述した関数がレンダラーで実行される．

## contextBridge
electronをrequireできるのはpreloadまで．
レンダラーで使用するために，contextBridgeを経由する．
```javascript:preload.js
const { contextBridge,ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('myAPI',{
   func1:()=>func1(),
   func2:async(arg)=>ipcRenderer.invoke('main-func2',arg),
   func3:async(arg)=>func3(arg),
});
```
```javascript:renderer.js
window.myAPI.func1();
window.myAPI.func2("data");
window.myAPI.func3("data");
```
func2とfunc3はrendererから引数を渡す．
func1,func3はpreloadで定義した関数を，
func2はメインプロセスでipcMain.invokeした関数を使用する．
# Electron-Store
Electronの設定情報を簡単に保存・読み出しができる．
[GitHubはこちら](https://github.com/sindresorhus/electron-store)
## インストール
```
npm install --save-dev electron-store
```
## 基本・仕様
store.getで設定の取得，store.setで設定の保存．
外部のjsonファイルに読み書きしてくれる．
同じKeyを使うことで，同じ設定項目に触ることが可能．
```javascript
const Store = require('electron-store');
const store= new Store();
// 設定の取得
let var1 = store.get("setting1","hogehoge")
console.log(var1)
var1="fugafuga"
// 設定の保存
store.set("setting1",var1)
```
store.getには初期値を入れることができ，登録した値がなければ初期値を入れる．
上記コードを実行すると，
初回：key"setting1"に値が登録されていないため，`get`では初期値の`"hogehoge"`を渡す．
　　　`set`()で変数`var1`に入っている`"fugafuga"`を保存．
2回目以降：key`"setting1"`に`"fugafuga"`が登録されているため，`get`では`"fugafuga"`を渡す．
　　　`set`()で変数`var1`に入っている`"fugafuga"`を保存．

`get`に初期値がなく，値が登録されていない場合，`undefined`が返ってくる．
`set`を実行しない限り設定は保存されないので，値が変更された時やアプリの終了時に`set`を実行すること．
設定は`C:\Users\ユーザー名\AppData\Roaming\アプリ名\config.json`にjson形式で記録される．
## 便利な使い方
Electron-Storeをそのまま使うと，Keyの管理が面倒．
そこで以下のようなファイルを作成・インポートすると比較的簡単に管理できる．
```javascript:main_setting.js
const Store = require('electron-store');
const store= new Store();
// Keyの管理
const settingKeys={
    key1:"setting1",
    key2:"setting2"
}
// 設定の取得
const setting_get = function(key){
    return store.get(key)
}
// 設定の保存
const setting_set = function(key,value){
    store.set(key,value)
}
module.exports={settingKeys,setting_get,setting_set}
```
```javascript:main.js
// インポート
const {settingKeys,setting_get,setting_set} = require('./main_setting.js')
// ～中略～
let var1 = setting_get(settingKeys.key1)
console.log(var1)
var1 = "fugafuga"
setting_set(settingKeys.key1,var1)
```
`main_setting.js`によってkey・読み書き関数を定義しExportすることで一括して管理ができる．
**※この方法を使うと最初の`get`は`undefined`が返ってくるので，別途初期値を`set`する必要がある．**

## 
# Python-Shell
Electron（NodeJS）からPythonを実行することができる．

長いので[こちらの記事](https://qiita.com/blue-skies_contrail/items/e36e9b48891f6ca9bf8e)分割しました．
# Electronの導入～起動まで
こちらの記事を参考にしています．
[【入門】Electron完全に理解した](https://zenn.dev/unsoluble_sugar/articles/c5b5faefddd35c1be8a3)

インストールの大まかな流れは，
- Gitのインストール
- NodeJSのインストール
- npmのインストール
- Electronのインストール
- Electronの起動
この時，Electronをグローバルインストールすると，`electron`コマンドが登録され，`electron .`でカレントディレクトリのアプリが起動できる．
## 初歩的なアプリの作成
上記インストール後，簡単なアプリを作成する．
1. アプリを作成するディレクトリへ移動．
2. `npm init`を実行．以下のメッセージが出てくるので，Enterで進める．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2748346/cab0bb66-f13c-b314-d73e-6e1d95ae0350.png)
完了すると，同じディレクトリにpackage.jsonが作成される．
3. `npm install --save-dev electron@latest`を実行．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2748346/3241cbce-a453-3493-ce88-10dde34ff312.png)
完了すると，同じディレクトリにElectron等のライブラリが入った`node_modules`フォルダが作成される．
3. 必要なファイルを作成  
同じディレクトリに以下のファイルを作成
・ main.js
└アプリ開始時に実行されるファイル．メインプロセス．
・ preload.js
└メインプロセスとレンダラープロセスを中継する．
・ index.html
└表示する画面を描画する．レンダラープロセス．
main.js
```javascript:main.js
const { app,Menu,MenuItem,BrowserWindow,ipcMain,dialog,desktopCapturer, nativeImage,screen,globalShortcut} = require('electron');
const path = require('path');
const fs = require('fs');
let win1;
//画面を作成する関数
const createMainWindow = function(w,h){
    win1 = new BrowserWindow({
        width: w,
        height: h,
        webPreferences:{
            contextIsolation: true,
            useContentSize: true,
            //__dirname:'現在のパス' に 'preload.js'を結合
            preload:path.join(__dirname,"./preload.js")
        }
    });
    //win1.webContents.openDevTools();
    win1.loadFile(path.join(__dirname,"./index.html"));
    return win1
}
// アプリ起動時のイベント．画面を作成．
app.whenReady().then(()=>{
    win1=createMainWindow(1000,800);
});
// アプリ終了時のイベント
app.on('window-all-closed', () => {
    app.quit();
});
```
preload.js
```javascript:preload.js
const { contextBridge,ipcRenderer } = require('electron');
```
index.html
```html:index.html
<html>
    <body>
        <p>hello world</p>
    </body>
</html>
```
5. package.jsonを開き，main.jsを登録する．
"main"に，作成したmain.jsを登録する．
"scripts"に，Electronを起動するコマンドを追加する．
```json:package.json
{
  "name": "recture_app",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node_modules\\electron\\dist\\electron.exe"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^22.0.0"
  }
}
```
6. `npm start`でelectronの実行．
# アプリのビルド
完成したアプリをビルドし，.exeで実行できるようにする
こちらの記事を参考にしています．
[Electron アプリの配布パッケージを作る (electron-builder)｜まくろぐ](https://maku.blog/p/2tcs8n2/)
- yarn,electron-builderのインストール
yarnをインストールし，yarnによってelectron-builderをインストール
```
> npm install -g yarn
> yarn add electron-builder --dev
```
- アプリをビルド
.exeを作成する．`dist/`以下に作成される．
```
ポータブルパッケージの作成
> npx electron-builder --win --x64 --dir
インストーラーの作成
> npx electron-builder --win --x64 
```
# Electronのバージョン管理
npmを使った、Electronのバージョン確認＆アップデート
Electronのバージョン確認
`npm list --depth=0 -g`でインストール済みのライブラリを確認
`npm view (ライブラリ名)`でライブラリの最新バージョンを確認
```
# npmで(グローバル)インストールしたライブラリのバージョン確認
npm list --depth=0 -g
# Electronのバージョン確認。
npm view electron 
# electronの最新バージョンをインストール
npm install electon@22.0.0  
```

# 参考文献
- はじめに
    - [はじめに | Electron](https://www.electronjs.org/ja/docs/latest)
- Electronの導入～起動まで
    - [【入門】Electron完全に理解した](https://zenn.dev/unsoluble_sugar/articles/c5b5faefddd35c1be8a3)
    - [Electronの環境構築（for Windows） - Qiita](https://qiita.com/TigRig/items/64d55b5fc5483b01c3b5)
- アプリのビルド
    - [Electron アプリの配布パッケージを作る (electron-builder)｜まくろぐ](https://maku.blog/p/2tcs8n2/)
- Electronのバージョン確認
    - [[Electron]アップデート方法(バージョン指定・ベータ版対応)](https://www.curict.com/item/7d/7da6204.html)
- Main⇔Rendererの通信
- Electron-Store
    - [GitHub - sindresorhus/electron-store: Simple data persistence for your Electron app or module - Save and load user preferences, app state, cache, etc](https://github.com/sindresorhus/electron-store)
    - [Electron で設定情報を扱う (electron-store)｜まくろぐ](https://maku.blog/p/ev6env5/)
    - [[Electron] 設定情報をローカルファイルに簡単保存 - electron-store](https://blog.katsubemakito.net/nodejs/electron/electron-store)