← Назад к курсу

Пособие: Electron — создаём десктопное приложение с нуля

Это подробное пособие по Electron — фреймворку для создания кроссплатформенных десктопных приложений на HTML, CSS и JavaScript.


1. Что такое Electron?

Electron позволяет разрабатывать нативные десктопные приложения для Windows, macOS и Linux, используя веб-технологии. В основе лежит Node.js + Chromium. Примеры известных приложений: Visual Studio Code, Slack, Discord, Figma, Notion.

Как это работает?
Каждое приложение Electron состоит из двух процессов:

  • Main (главный процесс) — отвечает за создание окон, управление жизненным циклом приложения, доступ к API операционной системы. Имеет полный доступ к Node.js.
  • Renderer (процесс рендеринга) — показывает интерфейс (HTML/CSS/JS). Каждое окно — отдельный процесс рендеринга. Может использовать часть API Node.js (ограниченно).

Для обмена данными между процессами используется IPC (Inter-Process Communication).

2. Подготовка окружения

Убедитесь, что установлен Node.js (версия 14 или выше):

node -v

Создайте папку для проекта и инициализируйте его:

mkdir my-electron-app
cd my-electron-app
npm init -y

Установите Electron как зависимость:

npm install electron --save-dev

В файле package.json измените точку входа и добавьте скрипт запуска:

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  }
}

3. Минимальное приложение

Создайте три файла: main.js (главный процесс), index.html (интерфейс), renderer.js (логика окна).

main.js

const { app, BrowserWindow } = require('electron');
const path = require('node:path');

function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'), // безопасный мост
            // nodeIntegration: false (по умолчанию безопасно)
        }
    });
    win.loadFile('index.html');
    // win.webContents.openDevTools(); // для отладки
}

app.whenReady().then(() => {
    createWindow();

    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) createWindow();
    });
});

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit();
});

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Моё Electron приложение</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Привет, Electron!</h1>
    <button id="infoBtn">Информация о системе</button>
    <p id="output"></p>
    <script src="renderer.js"></script>
</body>
</html>

preload.js (мост для безопасного общения с main)

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
    getSystemInfo: () => ipcRenderer.invoke('get-system-info')
});

renderer.js

const btn = document.getElementById('infoBtn');
const output = document.getElementById('output');

btn.addEventListener('click', async () => {
    const info = await window.electronAPI.getSystemInfo();
    output.textContent = `OS: ${info.os}, платформа: ${info.platform}, версия Node: ${info.nodeVersion}`;
});

Теперь добавим обработку IPC в main.js:

const { app, BrowserWindow, ipcMain } = require('electron');

// ... createWindow и прочее

ipcMain.handle('get-system-info', () => {
    return {
        os: process.platform,
        platform: process.platform,
        nodeVersion: process.versions.node
    };
});

4. Запуск

Выполните в терминале:

npm start

Откроется окно с кнопкой. После нажатия получите данные о системе.

5. Разбираем ключевые концепты

Главный процесс (main.js)

  • Один главный процесс на всё приложение.
  • Управляет окнами (BrowserWindow), меню, диалогами (открыть/сохранить файл), треем.
  • Перехватывает события системы: ready, window-all-closed, before-quit.

Процесс рендерера (каждое окно)

  • Загружает HTML, работает как обычное веб-окно.
  • Из соображений безопасности не имеет прямого доступа к Node.js (по умолчанию). Чтобы безопасно вызывать функции main-процесса, используется preload.js и contextBridge.

IPC (межпроцессное взаимодействие)

  • Одностороннее (renderer → main): ipcRenderer.send + ipcMain.on.
  • Двустороннее (запрос-ответ): ipcRenderer.invoke + ipcMain.handle (как в примере выше).
  • Отправка из main в renderer: win.webContents.send('event-name', data) + в renderer через ipcRenderer.on.

6. Добавляем фишки: диалоги, доступ к файлам, меню

Простой диалог выбора файла (main.js)

const { dialog } = require('electron');

ipcMain.handle('select-file', async () => {
    const result = await dialog.showOpenDialog({
        properties: ['openFile']
    });
    return result.filePaths[0];
});

В preload.js добавить экспорт selectFile: () => ipcRenderer.invoke('select-file'), в renderer.js вызвать.

Создание нативного меню (main.js)

const { Menu } = require('electron');
const template = [
    {
        label: 'Файл',
        submenu: [
            { label: 'Открыть', click: () => console.log('Открыть') },
            { role: 'quit', label: 'Выйти' }
        ]
    }
];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);

Работа с файловой системой (через IPC)

Из renderer-процесса нельзя напрямую использовать fs. Но можно сделать обёртку в main:

ipcMain.handle('write-file', (event, path, content) => {
    const fs = require('fs');
    fs.writeFileSync(path, content);
    return true;
});

7. Упаковка и распространение

Для сборки готового приложения используйте electron-builder или electron-packager.

Установка electron-builder

npm install electron-builder --save-dev

В package.json добавьте:

"build": {
  "appId": "com.example.myapp",
  "productName": "Моё приложение",
  "directories": {
    "output": "dist"
  },
  "files": [
    "**/*",
    "!node_modules/.bin"
  ],
  "win": {
    "target": "nsis",
    "icon": "icon.ico"
  },
  "mac": {
    "target": "dmg",
    "icon": "icon.icns"
  },
  "linux": {
    "target": "AppImage",
    "icon": "icon.png"
  }
}

Добавьте скрипт в package.json:

"scripts": {
  "dist": "electron-builder",
  "dist:win": "electron-builder --win",
  "dist:mac": "electron-builder --mac",
  "dist:linux": "electron-builder --linux"
}

Затем выполните npm run dist. Готовые установщики появятся в папке dist/.

8. Продвинутые советы и best practices

  • Безопасность – всегда выключайте nodeIntegration: false, используйте contextIsolation: true (по умолчанию в современных версиях), не загружайте удалённый HTML.
  • Отладка – используйте Ctrl+Shift+I (DevTools) в окне или win.webContents.openDevTools() в коде.
  • Горячая перезагрузка – установите electron-reload для разработки.
  • Работа с базами данных – используйте sqlite3 или better-sqlite3 в главном процессе, общайтесь через IPC.
  • Автообновление – electron-updater (часть электрон-билдера).
  • Управление состоянием – можно использовать Redux, MobX или просто localStorage / electron-store для хранения настроек.

9. Пример: приложение-заметки с сохранением в файл

Идея для закрепления:

  • Главное окно с textarea и кнопкой «Сохранить».
  • Диалог выбора папки (через dialog.showSaveDialog).
  • Main получает путь и содержимое, сохраняет текст в файл.
  • Добавить меню «Файл / Открыть» для загрузки заметки.

Это покроет все базовые механизмы Electron.

10. Где узнать больше?


Поздравляю! Теперь у вас есть фундамент для создания настольных приложений на веб-технологиях. Начинайте с простых утилит, постепенно добавляя нативные возможности — диалоги, уведомления, трей, горячие клавиши. Удачи в разработке!