In previous episode, we called some backend functions from the frontend through IPC channels. Now let's try it the other way.
It's similar, but not identical. Mostly because while there's one backend/main process, there could be a bunch of frontend/renderer processes, each with their window, so we can't just "send to frontend" like ipcMain.invoke
without being a bit more specific.
So can we do someWindow.webContents.invoke
? Well, also no. For complicated technical reasons Electron decided to not include this, and if you really need it, you need to use a third party library that emulates it with a bunch of calls. I think they should just include it in Electron.
For sending one way messages we can do someWindow.webContents.send
and that's all we'll do today.
But let's take it step by step.
Start a new application
We start the usual way:
$ npm init -y
$ npm install --save-dev electron
index.html
Nothing new here, just some styling, and placeholder for messages we'll receive from the backend:
<!DOCTYPE html>
<html>
<body>
<style>
body {
background-color: #444;
color: #ccc;
font-family: monospace;
font-size: 24px;
}
</style>
<h1>Messages from the backend:</h1>
<div id="messages"></div>
<script src="app.js"></script>
</body>
</html>
index.js
We need to start a frontend as usual, except this time we also want to save the window object, so we can send messages to it.
let { app, BrowserWindow } = require("electron")
let win
function createWindow() {
win = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
}
})
win.loadFile("index.html")
}
app.on("ready", createWindow)
app.on("window-all-closed", () => {
app.quit()
})
Now let's do the second step - let's read whatever is being typed on the terminal, and send it over!
let readline = require("readline")
let rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.on("line", async (line) => {
win.webContents.send("line", line)
})
app.js
Once we receive a message, just append it to the #messages
div.
As explained above, we can't really reply to this message, we'd need to do something a bit more complicated if we wanted responses as well.
let { ipcRenderer } = require("electron")
let messages = document.querySelector("#messages")
ipcRenderer.on("line", (event, line) => {
let message = document.createElement("div")
message.textContent = line
messages.appendChild(message)
})
What to do with all this?
In a real application, you'd want to declare the interface between frontend and backend, and put it all in preload.js
, so rest of your frontend can run without any special privileges.
Results
And here's the result:
As usual, all the code for the episode is here.
Top comments (0)