Розробка десктоп-приложения на Electron
Electron — фреймворк для створення кросс-платформенних десктоп-приложений на базі Chromium та Node.js. VS Code, Slack, Figma, GitHub Desktop — усе написано на Electron. Головна перевага: одна кодова база, три платформи. Головний недолік: розмір дистрибутива від 80 МБ.
Архітектура: Main та Renderer процеси
Electron розділяє код на два ізольовані процеси:
Main process — середовище Node.js з доступом до файлової системи, ОС, нативних API. Управляє вікнами, системним треєм, нативними меню.
Renderer process — Chromium, рендерить веб-контент. Без прямого доступу до Node.js (якщо не включений nodeIntegration: true, що небезпечно). Спілкування з main — лише через IPC.
main.js (Node.js)
├── BrowserWindow
│ └── renderer (Chromium + preload script)
├── Tray
├── Menu
└── IPC handlers
Мінімальна структура проекта
my-app/
├── package.json
├── main/
│ ├── index.js # точка входу main process
│ ├── preload.js # мост між main та renderer
│ └── ipc-handlers.js # IPC обробники
├── renderer/ # React/Vue/звичайний HTML
│ ├── index.html
│ └── src/
└── resources/
└── icon.png
{
"main": "main/index.js",
"scripts": {
"start": "electron .",
"build": "electron-builder"
},
"devDependencies": {
"electron": "^31.0.0",
"electron-builder": "^24.0.0"
}
}
Main process: створення вікна
// main/index.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 800,
minHeight: 600,
titleBarStyle: 'hiddenInset', // macOS — кастомний заголовок
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true, // обов'язково для безпеки
nodeIntegration: false, // відключити для безпеки
sandbox: true
}
});
if (process.env.NODE_ENV === 'development') {
mainWindow.loadURL('http://localhost:3000');
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'));
}
mainWindow.on('closed', () => { mainWindow = null; });
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
Preload script: безпечний мост
// main/preload.js
const { contextBridge, ipcRenderer } = require('electron');
// Експортуємо лише потрібне API в renderer
contextBridge.exposeInMainWorld('electronAPI', {
// Файлова система
openFile: () => ipcRenderer.invoke('dialog:openFile'),
saveFile: (content) => ipcRenderer.invoke('fs:saveFile', content),
// Системні функції
getVersion: () => ipcRenderer.invoke('app:getVersion'),
minimize: () => ipcRenderer.send('window:minimize'),
maximize: () => ipcRenderer.send('window:maximize'),
close: () => ipcRenderer.send('window:close'),
// Підписка на події з main
onUpdateAvailable: (callback) => {
const listener = (_, info) => callback(info);
ipcRenderer.on('update:available', listener);
return () => ipcRenderer.removeListener('update:available', listener);
}
});
// main/ipc-handlers.js
const { ipcMain, app, dialog, BrowserWindow } = require('electron');
const fs = require('fs/promises');
ipcMain.handle('dialog:openFile', async () => {
const { canceled, filePaths } = await dialog.showOpenDialog({
filters: [
{ name: 'Text Files', extensions: ['txt', 'md'] },
{ name: 'All Files', extensions: ['*'] }
]
});
if (canceled) return null;
const content = await fs.readFile(filePaths[0], 'utf-8');
return { path: filePaths[0], content };
});
ipcMain.handle('app:getVersion', () => app.getVersion());
ipcMain.on('window:minimize', (event) => {
BrowserWindow.fromWebContents(event.sender)?.minimize();
});
Інтеграція з React (Vite + Electron)
Найзручніша комбінація — electron-vite:
npm create @quick-start/electron my-app
# Вибираємо React + TypeScript
Конфігурація electron.vite.config.ts з коробки налаштовує три точки входу: main, preload, renderer.
Для існуючого Vite-проекта:
npm install electron-vite --save-dev
Упаковка та дистрибуція
electron-builder — стандарт для сборки інсталяторів:
# electron-builder.yml
appId: com.yourcompany.myapp
productName: My Application
directories:
output: release/
files:
- main/**
- renderer/dist/**
- '!**/*.map'
mac:
category: public.app-category.productivity
icon: resources/icon.icns
target:
- dmg
- zip
win:
icon: resources/icon.ico
target:
- nsis
- portable
linux:
icon: resources/icons/
target:
- AppImage
- deb
- rpm
# Сборка для всіх платформ
npm run build -- --mac --win --linux
# Лише для поточної платформи
npm run build
Продуктивність: зменшення розміру бандла
Electron включає весь Chromium — 80-150 МБ мінімум. Можна зменшити:
-
electron-builderзcompression: maximum - Виключення невикористаних
node_modulesчерез конфігураціюfiles - ASAR архівування (включено за замовчуванням)
Для приложень, де розмір критичний, розглядайте Tauri (~5 МБ) як альтернативу.
Типовий таймлайн розробки
Базове приложение з UI + File I/O + Auto-update: 1-2 тижні. Повнофункціональне приложение з нативними меню, треєм, нотифікаціями, оновленнями та сборкою під всі платформи: 3-6 тижнів залежно від функціональності.







