JavaScript

Electron's IPC Communication

Before we can dive into IPC communication, we need to discuss the two process types available in Electron (main and renderer).

An Electron app always has one main process that runs package.json’s main script (main.js). The script (main.js) that runs in the main process can display a GUI by creating web pages. These web pages run in their own process, which is called the renderer process.

To communicate between main and renderer process we need a system and that system is in the IPC modules (ipcMain and ipcRenderer). These module allows us to send and receive messages between the processes.

ipcRenderer

The ipcRenderer module allow communication from a renderer process to the main process. The basic structure for sending a message asynchronously to main process is:

ipcRenderer.send (channel, [, arg1][, arg2], [,...})
  • channel : a string that is used as a message identifier.
  • arg1, arg2: optional values as arguments

Example:

//renderer.js
const ipc = require('electron').ipcRenderer;
ipc.send('hello','a string', 10);

To receive a reply of asynchronous message from the main process, Electron uses the following structure:

ipcRenderer.on(channel, listener)
  • channel : a string as message identifier
  • listener: a callback function

Example:

//renderer.js
ipc.on('fromMain', (event, messages) => {
 // do something
}

The ipcRenderer.once(channel, listener) works similar to the above method with one exception. It is the one time listener function for the event and removed after invoking:

//renderer.js
ipc.once('fromMain', (event, messages) => {
 // do something
}

We can also send a message to main process synchronously. The ipcRenderer.sendSync method is use to send synchronous message. This method blocks the process until the reply from the main process is not received:

//renderer.js
const ipc = require('electron').ipcRenderer; 
let reply = ipc.sendSync('helloSync','a string', 10);
console.log(reply)

ipcMain

The ipcMain module allows communication from the main process to a renderer process. The following example demonstrates how to receive a message from the renderer process and reply to it using event.returnValue (For synchronous IPC messages) or event.sender (For asynchronous IPC messages).

How to receive messages from the renderer process and reply to each:

//main.js
const electron = require('electron'),
ipc = electron.ipcMain;
/* remaining code
.
.
*/
//Receive and reply to synchronous message
ipc.on('helloSync', (event, args) => {
 //do something with args
 event.returnValue = 'Hi, sync reply';
});

//Receive and reply to asynchronous message
ipc.on('hello', (event, args) => {
 event.sender.send('asynReply','Hi, asyn reply'); 
});

The callback function has two parameters:

  • event : The event object can respond to the sender, so we don’t need to write more code to send reply:
    • event.returnValue = args : to reply a synchronous message.
    • event.sender.send(channel,args): to reply an asynchronous message.
  • args : array contains the data that renderer process sent ('a string', 10)

IPC communication between renderer and main processes example

  • Create a new Electron’s project
  • Edit index.html and remove existing code in body tag except <script> require('./renderer.js');</script>
  • Create two buttons and a div in index.html:
//index.html
<input type="button" id="syncBtn" value="Hello Sync">
<input type="button" id="asyncBtn" value="Hello aSync">
<div id="reply"></div>
  • Edit the renderer.js file and add the following code:
//renderer.js
const
ipc      = require('electron').ipcRenderer,

syncBtn  = document.querySelector('#syncBtn'),
asyncBtn = document.querySelector('#asyncBtn');

let replyDiv = document.querySelector('#reply');

syncBtn.addEventListener('click', () => {
 let
 reply = ipc.sendSync('synMessage','A sync message to main');
 replyDiv.innerHTML = reply;
});

asyncBtn.addEventListener('click', () => {
 ipc.send('aSynMessage','A async message to main')
});

ipc.on('asynReply', (event, args) => {
 replyDiv.innerHTML = args;
});
  • Edit main.js and add the following code at the end of file:
//main.js
/*code
.
.
.
*/
const ipc = require('electron').ipcMain;
ipc.on('synMessage', (event, args) => {
 console.log(args);
 event.returnValue = 'Main said I received your Sync message';
});

ipc.on('aSynMessage', (event, args) => {
 console.log(args);
 event.sender.send('asynReply','Main said: Async message received')
});

Click here to download the ipc-example.zip which includes the project files: index.html, main.js, renderer.js and package.json.