Der Renderer-Prozess ist die UI-Welt deiner Electron-App — und im Kern ein vollwertiger Chromium-Tab. Du hast DOM, alle Web-APIs, modernste JavaScript-Features. Was du nicht hast: direkten Zugriff auf Node oder das Filesystem. Hier was im Renderer normal funktioniert und wo die Grenzen liegen.
Renderer = Chromium-Tab
Pro BrowserWindow ein Renderer-Prozess. Pro WebContentsView einer. Wer Multi-Window-App baut, hat mehrere parallele Renderer — sie teilen keinen Speicher und kommunizieren nur über IPC zum Main.
Was der Renderer kann:
- DOM, Canvas, WebGL, WebGPU
- Fetch, WebSocket, EventSource
- Web Workers, Service Workers
- IndexedDB, localStorage, sessionStorage
- Web Audio, MediaStream, getUserMedia
- WebAssembly
- Modernes ES2024+ (Chromium ist immer aktuell)
Was er nicht direkt kann:
fs,path,child_processund andere Node-APIs (ohne Bridge)- Andere Fenster steuern
- System-Tray, Menü, Dialog (das macht der Main)
Standard-HTML/JS funktioniert
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'">
<title>My App</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="app">
<h1>Hallo</h1>
<button id="load">Daten laden</button>
<pre id="output"></pre>
</div>
<script type="module" src="./renderer.js"></script>
</body>
</html>// Standard-DOM
const button = document.getElementById('load');
const output = document.getElementById('output');
// Web-API: fetch
button.addEventListener('click', async () => {
const res = await fetch('https://api.example.com/data');
output.textContent = JSON.stringify(await res.json(), null, 2);
});Das ist exakt der Code, den man auch auf einer normalen Webseite schreiben würde. Funktioniert ohne Anpassung.
Über IPC zum Main
Sobald Node-Funktionalität gebraucht wird (Datei lesen, Dialog öffnen, Settings speichern): der Renderer fragt den Main per IPC.
// window.api wird vom Preload-Skript bereitgestellt
async function openConfig() {
const path = await window.api.openFile();
if (!path) return;
const content = await window.api.readFile(path);
document.getElementById('config').textContent = content;
}window.api ist nichts Eingebautes — das ist eine Bridge, die du im Preload-Skript baust. Mehr im Artikel Preload-Skripte.
Renderer ist nicht der Web-Browser
Trotz Chromium gibt es Electron-spezifische Eigenheiten:
| Aspekt | Web-Browser | Electron-Renderer |
|---|---|---|
| User-Agent | Browser-Identifikation | Enthält Electron/X.Y.Z |
| CORS | Streng | bei file:// lockerer |
| Permission-Prompts | User klickt zu | Default-Ja, von App-Konfig steuerbar |
| LocalStorage-Quota | ~10 MB | quasi unbegrenzt |
| Service-Worker | Voll | funktioniert, aber selten relevant |
window.open | Browser-Fenster | von Main steuerbar |
Wer eine Web-App nach Electron portiert, sollte diese Eigenheiten kennen — manche Annahmen aus der Web-Welt halten nicht 1:1.
Mehrere Renderer
const mainWin = new BrowserWindow({ width: 1200, height: 800 });
mainWin.loadFile('main.html');
const settingsWin = new BrowserWindow({ width: 600, height: 400 });
settingsWin.loadFile('settings.html');Zwei BrowserWindow-Instanzen → zwei Renderer-Prozesse. Sie kennen sich nicht, kein gemeinsamer State im Speicher. Wenn das Settings-Fenster eine Änderung speichert und das Hauptfenster sie sehen soll: beide hängen am Main als Hub.
ipcMain.handle('settings:update', (_event, newSettings) => {
saveSettings(newSettings);
// alle Renderer benachrichtigen
BrowserWindow.getAllWindows().forEach(win => {
win.webContents.send('settings:changed', newSettings);
});
});DevTools im Renderer
Standardmäßig verfügbar — wie im normalen Chrome.
// Aus dem Main heraus
win.webContents.openDevTools();
win.webContents.openDevTools({ mode: 'detach' }); // separates Fenster
// Tastenkürzel funktionieren auch:
// Cmd+Alt+I (macOS)
// Ctrl+Shift+I (Windows/Linux)In Production typisch deaktiviert (außer für Beta-Channels), während Dev offen.
Interessantes
Renderer ist Chromium — modernste Web-Features verfügbar.
Electron 32 nutzt Chromium 128 — also alle modernen Web-APIs out of the box. Kein Polyfill nötig für Optional Chaining, Nullish Coalescing, Top-Level Await, Web Components etc.
Trotz Chromium: das ist kein Browser-Tab.
Manche Web-Standards verhalten sich anders (CORS bei file://, Permission-Defaults, Quota). Wer eine Web-App nach Electron portiert: prüfen, ob alle Annahmen halten.
Multi-Renderer brauchen den Main als Hub.
Zwei Fenster wissen nichts voneinander. Wer State teilt: über IPC zum Main, der dann Broadcast an alle Renderer macht. Direkte Renderer-zu-Renderer-Kommunikation gibt's nicht.
window.opener und window.open verhalten sich speziell.
Standard-Web öffnet ein neues Fenster im Browser. In Electron wird das vom Main abgefangen — über webContents.setWindowOpenHandler lässt sich entscheiden, was passiert. Default ist „neues BrowserWindow".
Globaler State zwischen Renderer-Sessions = Storage.
Beim Schließen und Wieder-Öffnen eines Fensters wird der Renderer neu instanziiert — JS-State ist weg. Persistente Daten gehören in localStorage (für simple Sachen) oder in den Main-Prozess via electron-store/SQLite.
Process-Variablen sind beschränkt.
Im Sandbox-Renderer ist process nur teilweise verfügbar (process.versions, process.platform ja; process.env selektiv). Wer mehr braucht: über Preload exposen.
Weiterführende Ressourcen
Externe Quellen
- Process Model
- WebContents
- Chromium Features Status — was wann verfügbar