メモ
WEB技術でデスクトップアプリケーションを開発できるFWのElectronについて、メモしました。
目次
- IPC通信について:メインプロセスとレンダラプロセス
- IPC通信とは何か?
-
main.js
の説明ipcMain.handle()メソッド
-
renderer.js
の説明ipcRenderer.invoke()メソッド
-
preload.js
の説明 - アプリケーションの実行方法
IPC通信とは何か?
メインプロセス側: main.js
ipcMain.handle()
メソッドを使用します。
ipcMain
モジュールはメインプロセスで、レンダラプロセスから送信されるメッセージを受信して処理します。
基本的にメインプロセスは受け身で受信したら送信元のレンダラプロセスに対して返信するみたいな動きになります。
レンダラプロセス側: renderer.js
ipcRender.invoke()
メソッドを使用します。
メインプロセスに対して、同期、非同期のメッセージを送信できるメソッドが用意されています。もちろん返信を受け取ることもできます。
メインプロセスとレンダラプロセスの橋渡し役: preload.js
preload.js
では Node.jsの機能が使用できます。
preload.js
にてipcRenderer
を利用できるようにするためには、メインプロセスであるmain.js
内で下記のように設定しておく必要があります。
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// ここに、preload.jsに関する記述を行う
preload: path.join(__dirname, 'preload.js')
}
})
エントリポイントについて
Electronと似ているFWのNW.jsなどもWEB技術でデスクトップアプリの開発が可能ですが、Eletronの差異の1つにエントリポイントの指定方法があります。
Nw.jsの場合は、HTMLファイルを直接指定するようなのですが、Electronの場合は、main.js
といったJSファイルをpackage.json
などでエントリーポイントとして指定し、そのJSファイルのメソッド中で、mainWindow.loadFile("index.html");
といった形で、具体的なHTMLエントリーポイントを柔軟に制御することができるようです。
メインプロセスについて
最初に起動するエントリポイントとなっているファイル、package.json
の “main” に設定されているjsファイルが動くのがメインプロセスです。
Node.jsで動くのでOSネイティブのAPIを使えます。
Fileの読み書きなどを行う場合はこのメインプロセスで行う必要があります。
このメインプロセスを終了するとアプリケーションが終了します。
レンダラプロセスについて
画面のレンダリングを行っているプロセスです。ブラウザで表示されているhtmlファイルの数だけ、つまりタブの数だけレンダラプロセスがあるイメージです。
ElectronはChromiumで動いているのでこのような仕組みになっています。
したがって当然ブラウザ上で動くJavaScriptと同じ機能しか使えません。
ElectronではIPCを行うためのモジュールである ipcMain
とipcRenderer
が提供されます。これを使ってプロセス間での通信を実現します。
IPCには同期通信と非同期通信の2種類があります。基本的には非同期で使うのがいいと思います。
contextBridge
について
ただし、contextBridge API の用法には注意が必要な点もあります。たとえば以下のコードは、contextBridge を利用しているにもかかわらず危険です。
この記述は危険
この myAPI.renderer() は ipcRenderer という強力な API を無制限かつ包括的にレンダラープロセスへ曝してしまっているからです。
const { ipcRenderer, contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
// NGな記法
renderer: ipcRenderer
})
推奨する記法
IPC ベースの API を公開する正しい方法は、代わりに IPC メッセージごとに 1 つのメソッドを提供することです。
「IPCメッセージ(のチャンネル)ごとに1つのメソッドを提供する」ように書き直すと次のようになります。
const { ipcRenderer, contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
openDialog: async () => ipcRenderer.invoke('open-dialog'),
})
アプリケーションの起動・実行
npx electron ./src
で可能です。
余談ですが、package.json
のscriptsに下記を記述することで、コマンドをカスタマイズできます。
"start": "npx electron ./src"
これで、npm run start
で起動することができます。
参考記事
-
最新版で学ぶElectron入門
https://ics.media/entry/7298/ -
Erectronでマルチプラットフォームなデスクトップアプリケーションを作ろう
https://zenn.dev/isana_citrus/articles/233072fb48b5d6