Grundlagen
Die Inter-Process Communication (IPC) bildet das Rückgrat der Kommunikation zwischen Main- und Renderer-Prozessen in Electron-Anwendungen. Diese Schnittstelle ermöglicht den sicheren und effizienten Datenaustausch zwischen den isolierten Prozessen der Anwendungsarchitektur. Durch die klare Trennung der Prozessverantwortlichkeiten bietet IPC nicht nur verbesserte Sicherheit, sondern auch optimierte Performance bei Desktop-Anwendungen. Das Verständnis der IPC-Grundlagen ist essenziell für die Entwicklung robuster und reaktionsschneller Electron-Anwendungen mit nativer Funktionalität.
Inhaltsverzeichnis
Einführung
IPC steht für Inter-Process Communication. IPC ist der Kommunikationsmechanismus zwischen den beiden zentralen Prozessen einer Electron-App.
Main Prozess
Das ist der Kern einer Anwendung. Hier laufen NodeJS-Apis, Systemzugriffe, Dateisystem, Window-Management usw.
Renderer Prozess
Jeder Renderer-Prozess läuft in einem eigenen Browser-Window oder Tab. Er ist im Prinzip wie ein isoliertes Browserfenster (basiert auf Chromium) und rendert das UI (HTML, CSS, JS).
Anzahl Prozesse
Main: Es gibt nur einen Main-Prozess.
Renderer: Es kann einen oder mehrere Renderer-Prozesse geben.
Wichtig
Main und Renderer laufen isoliert voneinander (verschiedene Prozesse), haben aber gemeinsam Zugriff auf den IPC-Bus, um Nachrichten und Events auszutauschen.
Grundstruktur
Bevor wir uns das Thema IPC anschauen, brauchen wir eine Anwendung, auf der wir aufbauen können.
Wir starten mit dem Main Process (Backend), nämlich der main.js
Datei. Die Datei kann auch anders genannt werden. Hierbei handelt es sich um einen Einstiegspunkt in die Anwendung.
import { app, BrowserWindow } from 'electron';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, "preload.js")
}
});
// HTML-Datei laden
mainWindow.loadFile("index.html");
// Event: Fenster geschlossen
mainWindow.on("closed", () => {
mainWindow = null;
});
}
// Events
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
Über die preload.js
wird später ausführlicher gesprochen. Aktuell erstellen wir sie nur mit einer minimalen Funktion, nämlich einer Log-Ausgabe.
console.log('Preload Script geladen');
Da Electron auf Web-Technologien basiert, braucht es irgendeine HTML-Datei, die verwendet wird. In unserer main.js
wurde index.html
angegeben. Daher muss dieser erstellt werden.
Hierbei handelt es sich um den Renderer Process (Frontend).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron IPC Tutorial</title>
<style>
body {
font-family: monospace;
margin: 20px;
background-color: #f0f0f0;
}
.container {
max-width: 800px;
margin: 0 auto;
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333333;
}
.step {
margin: 20px 0;
padding: 15px;
border: 1px solid #dddddd;
border-radius: 5px;
}
button {
color: #ffffff;
background-color: #007acc;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin: 5px;
}
button:hover {
background-color: #005a9e;
}
.output {
background-color: #f8f8f8;
border: 1px solid #dddddd;
padding: 10px;
margin-top: 10px;
border-radius: 3px;
min-height: 50px;
}
</style>
</head>
<body>
<h1>Electron IPC</h1>
<p>Dies ist der Renderer-Prozess</p>
<div class="step">
<h3>Grundlegendes Setup</h3>
<p>App läuft ordnungsgemäß</p>
</div>
</body>
</html>
Damit haben wir eine grundlegende App, die einfach eine HTML-Datei lädt.
Sichere Brücke - Context Bridge
In diesem Part bauen wir eine Brücke zwischen dem Frontend (Renderer) und dem Backend (Main) mit einer preload.js
Datei auf. Dies ist eine entscheidene Sicherheitsmaßnahme.
Warum Preload? Der Renderer-Prozess (HTML/JS) sollte aus Sicherheitsgründen keinen direkten Zugriff auf NodeJS APIs haben. Das preload.js
Skript läuft in einer privilegierten Umgebung, die Zugriff auf beides hat: Die window
und document
Objekte des Renderers und die NodeJS-Umgebung.
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
showMessage: () => ipcRenderer.invoke('showMessage', 'Hello Electron');
});
Mit dieser Definition ist der API-Punkt showMessage
über window.electronAPI.showMessage()
verfügbar.
Die Funktion exposeInMainWorld
erwartet zwei Argumente.
- Name der API (Welt)
- Konfiguration der API-Punkte, welche eine Brücke darstellen und IpcRenderer-Funktionen aufrufen.