Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

IPC: from the main process to the page

Sometimes an event happens in the main process but the page must react to it: a menu item was chosen, the window lost focus, a file changed. Then the main process sends a message to a specific window with webContents.send, and the page subscribes to the channel in advance. Such a message expects no answer.

Sending from the main process

webContents is the window object that controls its page. Add to createWindow in main.js:

// main.js
function createWindow() {
  const win = new BrowserWindow({
    width: 900,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });
  win.loadFile('index.html');
 
  win.on('focus', () => win.webContents.send('window:focus', true));
  win.on('blur', () => win.webContents.send('window:focus', false));
}

When the window gains or loses focus, the page receives a message on the window:focus channel with true or false.

Subscribing in preload

The page cannot see ipcRenderer, so preload gives it a subscribe function:

// preload.js
const { contextBridge, ipcRenderer } = require('electron');
 
contextBridge.exposeInMainWorld('notes', {
  load: () => ipcRenderer.invoke('notes:load'),
  onFocusChange: (callback) => {
    ipcRenderer.on('window:focus', (event, focused) => callback(focused));
  },
});

ipcRenderer.on calls the listener for every message. Only the value goes to callback, without the event object: it holds references to IPC internals, and the page does not need them.

The page reacts

// renderer.js
window.notes.onFocusChange((focused) => {
  document.body.style.opacity = focused ? '1' : '0.6';
});

Switch to another app — the Notes window fades. Come back — it is bright again.

Unsubscribing

If the subscription is not needed all the time, preload can return an unsubscribe function:

// preload.js
onFocusChange: (callback) => {
  const listener = (event, focused) => callback(focused);
  ipcRenderer.on('window:focus', listener);
  return () => ipcRenderer.removeListener('window:focus', listener);
},

The page keeps what onFocusChange returned and calls it when the messages are no longer needed. React components unsubscribe this way when they unmount.

Both directions

DirectionMain processPreload
Page → main, with an answeripcMain.handleipcRenderer.invoke
Page → main, no answeripcMain.onipcRenderer.send
Main → pagewin.webContents.sendipcRenderer.on

Common mistake

A message sent right after loadFile is lost: the page has not loaded yet and has not subscribed to the channel. If data is needed at startup, either let the page request it with invoke, or send the message after the load event: win.webContents.on('did-finish-load', () => ...).

Thanks for reading!

Donate to the site — we work hard for you.