Electron.jsにてプロセス間通信を汎用的に実装したい

Electronを使用してデスクトップアプリを開発している中で、メインプロセスとレンダラープロセス間での通信処理を汎用的(使い回しできるよう)にしたいなということで、アイデアを紹介します。

本記事は、メモ書きのようなもので、SEOは特に考慮していません。
また、熟練者のようなコードではありませんので、あくまで参考になればと思って書いています。

サンプルソース

プリロードファイル(preload.ts)

import { contextBridge, ipcRenderer, IpcRendererEvent } from "electron"
contextBridge.exposeInMainWorld("myAPI", {
  // renderer -> main
  send: (
    channel: string,
    ...args: any[]
  ) => ipcRenderer.send(channel, args),
  // main -> renderer
  on: (
    channel: string,
    callback: (event: IpcRendererEvent, ...args: any[]) => any
  ) => ipcRenderer.on(channel, (event, args) => callback(event, args)),
})

プリロードファイルが一番重要かと思い、最初に記述しました。
メインとレンダラーのプロセス間送受信を実現しています。

メインファイルの送受信処理

// レンダラーに送信
mainWindow.webContents.send("channel:a", args)
// レンダラーから受信(リスナー)
ipcMain.on("channel:b", (args) => {
  // 好きな処理
})

// リスナーの削除(一応書いときます)
ipcMain.removeAllListeners("channel:b")

レンダラーファイルの送受信処理

// メインから受信
window.myAPI.on("channel:a", (_event, args) => {
  // 好きな処理
})

// メインに送信
window.myAPI.send("channel:b", args)

メインファイル、レンダラーファイル共に「args」の部分は好きなように設定してください。
レンダラーの処理は、windowオブジェクトが生成されていないとエラーになるので、私はuseEffect内に記述するようにしましたが、この方法が正しいのか不安です…動くからいっか

インターフェースファイル(any多くてすみません)

declare global {
  interface Window {
    myAPI: IMyAPI
  }
}

export interface IMyAPI {
  send: (channel: string, ...args: any[]) => any
  on: (
    channel: string,
    callback: (event: IpcRendererEvent, ...args: any[]) => any
  ) => any
}

さいごに

すごく簡略した記述で、申し訳ないです…
Electron公式のドキュメントと見比べながら実装してみてください。
アドバイスとかあればくださいm(_ _)m

いいなと思ったら応援しよう!