Electronで最初に躓くメインプロセスとレンダラープロセスについて
さっそくElectronで開発をしようとしましたが、初見ではエントリポイントやメニューの操作、ローカルファイルへのアクセス方法や各画面との通信・ページ遷移の方法など、分からないことだらけです。
その中でも一番最初に躓くのは、Electronのプロセスが「メイン」と「レンダラー」の2つあることではないでしょうか。
Electronを学習する際は、このプロセスの理解から始めないといけなさそうです。
目次
- メインプロセスとレンダラープロセスのそれぞれの役割
- メインプロセスからレンダラープロセスへの通知
- レンダラープロセスからメインプロセスへの通知
メインプロセスとレンダラープロセスのそれぞれの役割
概要は公式サイトのドキュメントを見てもらうとして、仕組みとしては、最初にメインプロセスを立ち上げて、そのメインプロセスから画面用のレンダラープロセスが実行されるような感じです。
そういう仕組みであることはいいとして、これが開発にどう影響があるのかというと、とりあえずちょろっとアプリを作成してみた感じでは、メインプロセスはアプリのメニュー関連の処理、レンダラープロセスは画面ごとの処理、といった感じで使い分けていました。
例えば、メニューで「ファイルを開く」コマンドを用意して画像ファイル選択後、選択した画像を画面上に表示するといった処理を作る場合、「メニューからのファイル選択」はメインプロセス、画像ファイルの表示はレンダラープロセス、といったようになります。
そういった仕組みであるため、利用できるElectron用のAPIがメインとレンダラーで異なる点が、Electronアプリを作成する上で一番重要です。
また、メインプロセスとレンダラープロセス間で通信を行いたい場合、メインからの発信と、レンダラーからの発信で方法が異なります。
メインプロセスからレンダラープロセスへの通知
「メインプロセス」から「レンダラープロセス」へ通知する場合、以下のようなコードになります。
メイン側
const {app, BrowserWindow} = require('electron')
let win = null
app.on('ready', () => {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(`file://${__dirname}/index.html`)
win.webContents.on('did-finish-load', () => {
win.webContents.send('ping', 'pong')
})
})
レンダラー側
const { ipcRenderer } from 'electron'
ipcRenderer.on('ping', (event, arg) => {
console.log(arg) // pong
})
レンダラープロセスからメインプロセスへの通知
逆に「レンダラープロセス」から「メインプロセス」への通知、さらには「メインプロセス」処理後に「レンダラープロセス」へ処理を戻す場合は、以下のようなコードになります。
メイン側
const {ipcMain} = require('electron')
// 同期
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // ping
event.returnValue = 'pong'
})
// 非同期
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // ping
event.sender.send('asynchronous-reply', 'pong')
})
レンダラー側
const {ipcRenderer} = require('electron')
// 同期
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // pong
// 非同期
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // pong
})
ipcRenderer.send('asynchronous-message', 'ping')
上記の通知処理を使うことで、メインプロセスからの通知を別の画面で受け取ることも可能です。