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_process und andere Node-APIs (ohne Bridge)
  • Andere Fenster steuern
  • System-Tray, Menü, Dialog (das macht der Main)

Standard-HTML/JS funktioniert

HTML index.html
<!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>
JavaScript renderer.js
// 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.

JavaScript renderer.js
// 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:

AspektWeb-BrowserElectron-Renderer
User-AgentBrowser-IdentifikationEnthält Electron/X.Y.Z
CORSStrengbei file:// lockerer
Permission-PromptsUser klickt zuDefault-Ja, von App-Konfig steuerbar
LocalStorage-Quota~10 MBquasi unbegrenzt
Service-WorkerVollfunktioniert, aber selten relevant
window.openBrowser-Fenstervon 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

JavaScript main.js – mehrere Fenster
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.

JavaScript main.js – Broadcast
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.

JavaScript
// 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

/ Weiter

Zurück zu Renderer & Preload

Zur Übersicht