Electron IPC

7 min read

Electron has two processes named IPC Main and IPC Renderer for sending data between each other.

IPC Renderer usually called from the web page. It sends a request to the IPC Main which processes data and gives a response back.

IPC Renderer -> IPC Main -> IPC Renderer

This way you can transfer data between window and main process.

Code

Code examples are available in Electron Documentation: ipcMain.

Main process

const { ipcMain } = require('electron'); /** Define channel name and message */ const CHANNEL_NAME = 'main'; const MESSAGE = 'pong'; /** * SYNCHRONOUS */ ipcMain.on(CHANNEL_NAME, (event, data) => { console.log(data); // show the request data event.returnValue = MESSAGE; // send a response for a synchronous request }); /** * ASYNCHRONOUS */ ipcMain.on(CHANNEL_NAME, (event, data) => { console.log(data); // show the request data event.reply(CHANNEL_NAME, MESSAGE) // callback with a response for an asynchronous request });

Web page

const { ipcRenderer } = require('electron'); /** Define channel name and message */ const CHANNEL_NAME = 'main'; const MESSAGE = 'ping'; /** * SYNCHRONOUS */ console.log(ipcRenderer.sendSync(CHANNEL_NAME, MESSAGE)); // send request and show response /** * ASYNCHRONOUS */ ipcRenderer.send(CHANNEL_NAME, message); // send request ipcRenderer.on(CHANNEL_NAME, (event, data) => { // IPC event listener console.log(data); // show the response data });

Examples

Here is a package.json file for our sample Electron app.

{ "main": "main.js", "scripts": { "start": "electron ." }, "devDependencies": { "electron": "^5.0.1" } }

Create this file and run npm start to install required packages.

Then create a main.js script for the app.

const { app, BrowserWindow, ipcMain } = require('electron'); /** * Create a new window */ const createWindow = () => { let mainWindow = new BrowserWindow({ webPreferences: { /** Enable node integration */ nodeIntegration: true } }); /** Open devTools */ mainWindow.webContents.openDevTools(); /** Load the index.html page */ mainWindow.loadFile('index.html'); }; /** * Initialize the application */ const init = () => { /** Create app window */ createWindow(); /** Define channel name */ const CHANNEL_NAME = 'main'; /** * Add an IPC event listener for the channel */ ipcMain.on(CHANNEL_NAME, (event, data) => { /** Show the request data */ console.log(data); /** Send a response for a synchronous request */ event.returnValue = 'pong'; }) }; /** * Run the app */ app.on('ready', init);

And the last file is an index.html page.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>IPC test app</title> <script> const { ipcRenderer } = require('electron'); /** Define channel name */ const CHANNEL_NAME = 'main'; /** Create a processor for a button's click event */ const clickButton = () => { /** Message to be sent */ let message = 'ping'; /** Show response for a sync IPC request */ console.log(ipcRenderer.sendSync(CHANNEL_NAME, message)); } </script> </head> <body> <button onclick="clickButton()">Press me</button> </body> </html>

Now you can run this Electron app by the simple command npm start.

You will see a browser window with a one button on the page. Click it.

In the terminal with a running script ping will be shown. Also pong will be appeared in the browser's console.

Asynchronous requests

You can also send and process async requests.

Updated main.js file.

const { app, BrowserWindow, ipcMain } = require('electron'); let mainWindow; /** * Create a new window */ const createWindow = () => { mainWindow = new BrowserWindow({ webPreferences: { /** Enable node integration */ nodeIntegration: true } }); /** Open devTools */ mainWindow.webContents.openDevTools(); /** Load the index.html page */ mainWindow.loadFile('index.html'); }; /** * Initialize the application */ const init = () => { /** Create app window */ createWindow(); /** Define channel name */ const CHANNEL_NAME = 'main'; /** * Add an IPC event listener for the channel */ ipcMain.on(CHANNEL_NAME, (event, data) => { /** Show the request data */ console.log(data); /** Callback with a response for an asynchronous request */ event.reply(CHANNEL_NAME, 'pong') }) }; /** * Run the app */ app.on('ready', init);

Updated index.html file.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>IPC test app</title> <script> const { ipcRenderer } = require('electron'); /** Define channel name */ const CHANNEL_NAME = 'main'; /** Add IPC event listener */ ipcRenderer.on(CHANNEL_NAME, (event, data) => { console.log(data); }); /** Create a processor for a button's click event */ const clickButton = () => { /** Message to be sent */ let message = 'ping'; /** Send async request without waiting answer */ ipcRenderer.send(CHANNEL_NAME, message) } </script> </head> <body> <button onclick="clickButton()">Press me</button> </body> </html>

ipcMain to ipcRenderer

You can send data from ipcMain to ipcRenderer manually without waiting for a response via send() method of windows's content.

mainWindow is an instance of a BrowserWindow.

const CHANNEL_NAME = 'main'; const MESSAGE = 'tick'; setInterval(() => { mainWindow.webContents.send(CHANNEL_NAME, MESSAGE); }, 1000);

You can handle this event on the web page by ipcRenderer.

const CHANNEL_NAME = 'main'; ipcRenderer.on(CHANNEL_NAME, (event, data) => { console.log(data); });

Example

main.js file.

const { app, BrowserWindow, ipcMain } = require('electron'); /** Define window's variable in the global scope */ let mainWindow; /** * Create a new window */ const createWindow = () => { mainWindow = new BrowserWindow({ webPreferences: { /** Enable node integration */ nodeIntegration: true } }); /** Open devTools */ mainWindow.webContents.openDevTools(); /** Load the index.html page */ mainWindow.loadFile('index.html'); }; /** * Initialize the application */ const init = () => { /** Create app window */ createWindow(); /** Define channel name and message */ const CHANNEL_NAME = 'main'; const MESSAGE = 'tick'; /** Send message every one second */ setInterval(() => { mainWindow.webContents.send(CHANNEL_NAME, MESSAGE); }, 1000); }; /** * Run the app */ app.on('ready', init);

index.html file.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>IPC test app</title> <script> const { ipcRenderer } = require('electron'); /** Define channel name */ const CHANNEL_NAME = 'main'; /** Add IPC event listener */ ipcRenderer.on(CHANNEL_NAME, (event, data) => { console.log(data); }); </script> </head> <body> </body> </html>