Inter-Process Communication

This page describes step by step how to setup IPC between main and renderer processes

Preload Scripts

Preload Scripts contain code that is executed in the renderer process. These scripts run in renderer context but have more privileges by having access to Node.js APIs, allowing them to have access to the OS functions.

Lets start by adding a Preload Script to our application

1

Create a Preload Script

In the main directory create preload.mjs

preload.mjs
import { contextBridge, ipcRenderer } from "electron";

// Exposing methods using contextBridge
contextBridge.exposeInMainWorld("mavlink", {
});

2

Import Preload Script in main

main.js
import { BrowserWindow, app, ipcMain } from "electron";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

let win;

const createWindow = () => {
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.mjs"),
      contextIsolation: true,
      nodeIntegration: true,
    },
  });

  if (process.env.NODE_ENV === "development") {
    win.loadURL("http://localhost:5173");
  } else {
    win.loadFile(path.join(__dirname, "../../build/renderer/index.html"));
  }
};

app.whenReady().then(() => {
  createWindow();

  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

Using Inter-Process Communication

Renderer to Main (One-Way)

1

Listen for event on Main

main.js
import { app, BrowserWindow, ipcMain } from "electron";

const handler = (event,data) => {
    // Callback function to handle data
    }

app.whenReady().then()(() => {
    ipcMain.on("foo", handler);
    createWindow();
})
2

Expose ipcRenderer.send via Preload

preload.mjs
import { contextBridge, ipcRenderer } from "electron";

// Exposing methods using contextBridge
contextBridge.exposeInMainWorld("electronAPI", {
    bar: (data) => ipcRenderer.send("foo",data);
});
3

Call the function in Renderer

App.jsx
const buttonHandler = () => {
    window.electronAPI.bar(data);
}

Renderer to Main (Two-Way)

1

Listen for events with ipcMain.handle

main.js
import { app, BrowserWindow, dialog, ipcMain } from "electron";

const handler = async () => {
    return data;
}

app.whenReady().then(() => {
    ipcMain.handle("requestData", handler);
    createWindow();
})

2

Expose ipcRenderer.invoke via Preload

preload.js
import { contextBridge, ipcRenderer } from "electron";

// Exposing methods using contextBridge
contextBridge.exposeInMainWorld("electronAPI", {
    request: () => ipcRenderer.invoke("requestData");
});
3

Request data from Renderer

App.jsx
const buttonHandler = () => {
    data = await window.electronAPI.request();
}

Main to Renderer (One-Way)

1

Send message from Main

main.js
import { app, BrowserWindow, ipcMain } from "electron"
const senderFunction = () =>{
    win.webContnets.send()
}
2

Expose ipcRenderer.on via Preload

preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
  onData: (callback) => ipcRenderer.on('update-Data', (event, value) => callback(value))
})
3

Handle Data request in Renderer

App.jsx
window.electronAPI.onData((value) =>{
    //handle value here
})

Last updated