Observable IPC Channels
Tldr
Transform main-to-renderer communication channels into observables that you can process and subscribe to.
Main Process
The main process sends some data to the renderer process
on the count channel every 500ms.
main.js
const {app, BrowserWindow} = require('electron');
const path = require('path');
app.whenReady().then(async () => {
const bwin = new BrowserWindow({
width: 600,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.resolve(__dirname, 'preload.js')
}
});
await bwin.loadFile('renderer.html');
bwin.show();
bwin.webContents.openDevTools();
let count = 0;
setInterval(() => {
bwin.webContents.send('count', count++); // Send to renderer process.
}, 500);
});
Preload Script
The on method returns a pair of functions to be used with
RxJS's fromEventPattern function.
preload.js
const {contextBridge, ipcRenderer} = require('electron');
contextBridge.exposeInMainWorld('MY_APP', {
on: channel => ([
(handler) => { // addListener
function _handler(ev, ...args) {
console.log(`Received from channel '${channel}':`, ...args);
handler(...args);
}
console.log(`Start observing from ipcRenderer.on('${channel}')`);
ipcRenderer.on(channel, _handler);
return _handler;
}, // |
// +--+
// |
// v
(_, _handler) => { // removeListener
console.log(`Stop observing from ipcRenderer.on('${channel}')`);
ipcRenderer.removeListener(channel, _handler);
}
])
});
Renderer Page
We use the pair of functions returned by MY_APP.on('count')
with RxJS's fromEventPattern function to get an observable
on that channel. Every time the main process emits on that channel
that observable will emit the same thing.
renderer.html
<html>
<head>
<style>
body {background-color:black;color:limegreen}
</style>
<script src="https://unpkg.com/rxjs@7.5.5/dist/bundles/rxjs.umd.min.js"></script>
</head>
<body>
<div id="response"></div>
<script>
const {fromEventPattern} = rxjs;
const {take} = rxjs.operators;
const [addListener, removeListener] = window.MY_APP.on('count');
const count$ = fromEventPattern(addListener, removeListener).pipe(
take(5) // Unsubscribe automatically after 5 emissions.
);
count$.subscribe((count) => {
document.querySelector('#response').innerHTML += `${count}<br>`;
});
</script>
</body>
</html>
Screenshot
