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>