Приложение на базе Electron состоит из двух фундаментально разных типов процессов:
Такое разделение повторяет архитектуру браузера Chromium, внутри которого один процесс управляет жизненным циклом приложения, а отдельные процессы отвечают за отображение пользовательского интерфейса.
Основной процесс запускается первым и управляет:
Renderer-процесс представляет собой обычную веб-страницу, работающую внутри Chromium. Именно renderer отвечает за:
Одно Electron-приложение может содержать:
Main process начинается с файла, указанного в поле main
внутри package.json.
Пример:
{
"name": "electron-app",
"main": "main.js"
}
Файл main.js становится ядром приложения.
Главная задача main process — создание окон.
Пример минимального main process:
const { app, BrowserWindow } = require('electron');
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
app ожидает готовности движка Chromium.BrowserWindow.index.html.Событие ready означает, что Electron и Chromium
полностью инициализированы.
app.whenReady().then(() => {
console.log('Application ready');
});
До наступления готовности нельзя создавать окна.
Вызывается после закрытия всех окон.
app.on('window-all-closed', () => {
app.quit();
});
На macOS поведение обычно отличается: приложение остаётся активным даже без открытых окон.
Пример:
const { app } = require('electron');
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
Используется преимущественно на macOS.
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
BrowserWindow — оболочка над нативным окном операционной
системы.
const win = new BrowserWindow({
width: 1400,
height: 900,
minWidth: 800,
minHeight: 600
});
const win = new BrowserWindow({
frame: false
});
Такие окна используются для кастомных интерфейсов.
const win = new BrowserWindow({
transparent: true
});
const win = new BrowserWindow({
fullscreen: true
});
const win = new BrowserWindow({
show: false
});
win.once('ready-to-show', () => {
win.show();
});
Подход предотвращает мерцание интерфейса.
Renderer process — это изолированный браузерный процесс Chromium.
Он исполняет:
Каждое окно обычно имеет собственный renderer process.
win.loadFile('index.html');
win.loadURL('https://example.com');
Файл renderer.js:
document.getElementById('button').addEventListener('click', () => {
console.log('clicked');
});
HTML:
<button id="button">Click</button>
<script src="renderer.js"></script>
Renderer напоминает обычное frontend-приложение.
Главная особенность Electron — строгая изоляция между main и renderer.
Renderer по умолчанию:
Main process выступает посредником между интерфейсом и операционной системой.
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
});
После этого renderer получает доступ к:
const fs = require('fs');
Если renderer загружает внешний контент, злоумышленник сможет получить доступ к:
Поэтому современный Electron рекомендует:
nodeIntegration: false
Современная безопасная конфигурация:
const win = new BrowserWindow({
webPreferences: {
contextIsolation: true,
nodeIntegration: false
}
});
Preload script выполняется:
Пример:
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
});
const { contextBridge } = require('electron');
contextBridge.exposeInMainWorld('api', {
version: '1.0.0'
});
console.log(window.api.version);
Renderer получает только ограниченный API.
Так как процессы изолированы, Electron использует IPC:
ipcMainipcRendererconst { ipcRenderer } = require('electron');
ipcRenderer.send('save-file', {
text: 'Hello'
});
const { ipcMain } = require('electron');
ipcMain.on('save-file', (event, data) => {
console.log(data);
});
ipcRenderer.on('save-result', (event, result) => {
console.log(result);
});
event.reply('save-result', {
success: true
});
Современный подход для request-response взаимодействия.
const result = await ipcRenderer.invoke('read-config');
ipcMain.handle('read-config', async () => {
return {
theme: 'dark'
};
});
invoke/handle:
Современный безопасный вариант:
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
loadConfig: () => ipcRenderer.invoke('load-config')
});
const config = await window.electronAPI.loadConfig();
Renderer не получает прямого доступа к Electron API.
Доступ к Node.js рекомендуется выполнять только в main process.
const fs = require('fs');
ipcMain.handle('read-file', async () => {
return fs.readFileSync('data.txt', 'utf8');
});
Main process полностью управляет окнами.
const child = new BrowserWindow({
parent: mainWindow,
modal: true
});
win.close();
win.hide();
win.show();
win.webContents.send('message', {
text: 'Hello'
});
webContents — объект управления renderer process.
Он позволяет:
win.webContents.executeJavaScript(`
document.body.style.background = 'black';
`);
win.webContents.openDevTools();
win.webContents.on('did-finish-load', () => {
console.log('loaded');
});
Electron поддерживает sandbox-режим.
const win = new BrowserWindow({
webPreferences: {
sandbox: true
}
});
Sandbox дополнительно ограничивает renderer.
Безопасное Electron-приложение обычно использует:
webPreferences: {
contextIsolation: true,
sandbox: true,
nodeIntegration: false,
preload: preloadPath
}
Содержит:
Содержит:
Содержит:
Frontend-фреймворки работают исключительно внутри renderer process.
Пример:
main
├── BrowserWindow
└── React app
Electron не зависит от конкретного frontend-стека.
Каждое окно создаёт отдельный renderer process.
createMainWindow();
createSettingsWindow();
createAboutWindow();
Преимущества:
Недостаток — повышенное потребление памяти.
Если renderer падает, main process продолжает работать.
win.webContents.on('render-process-gone', (event, details) => {
console.log(details.reason);
});
Main process может:
Падение main process завершает всё приложение.
Поэтому:
Renderer может использовать:
new Worker('worker.js');
Это позволяет:
Renderer поддерживает:
Electron фактически запускает полноценный Chromium.
Ранее Electron предоставлял модуль:
require('@electron/remote');
Он позволял renderer напрямую вызывать main API.
Подход оказался небезопасным:
Современные приложения используют IPC и preload API вместо remote.
┌────────────────────┐
│ Main Process │
│────────────────────│
│ BrowserWindow │
│ app lifecycle │
│ filesystem │
│ native API │
│ IPC handlers │
└─────────┬──────────┘
│ IPC
▼
┌────────────────────┐
│ Preload Script │
│────────────────────│
│ contextBridge │
│ secure API │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ Renderer Process │
│────────────────────│
│ HTML │
│ CSS │
│ React/Vue │
│ DOM │
│ UI │
└────────────────────┘