Почему настольные приложения в 2025 году? Потому что веб — это не всё
Давайте будем честными — мы все любим JavaScript. Он повсюду. С его помощью можно создавать веб-приложения, мобильные приложения, инструменты CLI и даже умные тостеры (вероятно). Но есть одна область, которая иногда кажется забытой: настольные приложения. Конечно, можно утверждать, что веб-приложений достаточно, но есть что-то удовлетворяющее в создании нативно выглядящего приложения, которое работает офлайн, имеет реальный доступ к файловой системе и не требует от пользователей открытия ещё одной вкладки браузера.
Встречайте Electron: фреймворк, который позволяет создавать настольные приложения, используя те же технологии, которые вы уже знаете — HTML, CSS и JavaScript. Это технология, лежащая в основе популярных приложений, таких как VS Code, Slack, Discord и Figma. Если эти компании доверяют Electron для своих продуктов, возможно, это заслуживает вашего внимания.
Понимание архитектуры Electron
Прежде чем мы углубимся в код, давайте разберёмся, что делает Electron таким популярным. Представьте его как швейцарский армейский нож, сочетающий два мощных инструмента: Chromium (движок, стоящий за Chrome) и Node.js (среда выполнения JavaScript на стороне сервера). Объединив эти два компонента, Electron предоставляет вам лучшее из обоих миров — мощный движок рендеринга и полный доступ к операционной системе.
(Среда выполнения Node.js)
Полный доступ к ОС"] Preload["Предварительный скрипт
(Мост безопасности)"] Renderer["Процесс рендеринга
(Chromium)
UI и взаимодействие с пользователем"] Main -->|Сообщения IPC| Preload Preload -->|Предоставленные API| Renderer Renderer -->|Сообщения IPC| Main Main -->|Файл Система| OS["Операционная система"] Main -->|Системные API| OS
Приложение Electron имеет два основных процесса: главный процесс (Node.js с полным доступом к ОС) и процессы рендеринга (экземпляры Chromium, которые обрабатывают ваш UI). Они общаются через IPC (межпроцессное взаимодействие), а предварительные скрипты служат в качестве шлюза безопасности между ними.
Настройка вашего первого проекта Electron
Давайте перейдём к практике. Я проведу вас через создание простого, но полного настольного приложения — представьте это как «Hello Electron» на стероидах.
Шаг 1: Инициализация проекта
Создайте новую директорию и инициализируйте ваш проект:
mkdir my-awesome-app
cd my-awesome-app
npm init -y
npm install --save-dev electron
Почему Electron устанавливается как зависимость для разработки? Потому что, когда вы упаковываете своё приложение, Electron становится частью бандла. Вашим пользователям не нужно будет устанавливать Node.js отдельно — всё уже встроено. Удобно, правда?
Шаг 2: Настройка точки входа
Обновите ваш package.json, чтобы указать на ваш главный файл процесса и добавьте скрипт запуска:
{
"name": "my-awesome-app",
"version": "1.0.0",
"description": "Моё первое приложение Electron",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"devDependencies": {
"electron": "^31.0.0"
}
}
Шаг 3: Создание главного процесса
Создайте main.js в корне вашего проекта. Вот где начинается волшебство:
const { app, BrowserWindow } = require('electron');
const path = require('path');
let mainWindow;
// Создаём окно браузера, когда приложение готово
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
sandbox: true
}
});
// Загружаем файл index.html
mainWindow.loadFile('index.html');
// Открываем DevTools в режиме разработки (опционально)
mainWindow.webContents.openDevTools();
}
// Слушатели событий приложения
app.on('ready', createWindow);
app.on('window-all-closed', () => {
// На macOS приложения обычно остаются открытыми, пока их явно не закроют
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// На macOS заново создаём окно при клике по иконке в доке
if (mainWindow === null) {
createWindow();
}
});
Обратите внимание на объект webPreferences? Свойство preload указывает на скрипт, который мы создадим следующим шагом. Настройка sandbox: true делает ваше приложение более безопасным, изолируя процесс рендеринга.
Шаг 4: Создание HTML интерфейса
Создайте index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Моё крутое приложение Electron</title>
<!-- Стили -->
</head>
<body>
<div class="container">
<h1>🚀 Добро пожаловать в Electron</h1>
<!-- Содержимое -->
</div>
<script src="renderer.js"></script>
</body>
</html>
Шаг 5: Предварительный скрипт (Безопасность в первую очередь!)
Создайте preload.js. Это crucial — это ваша точка проверки безопасности:
const { contextBridge, ipcRenderer } = require('electron');
const os = require('os');
const path = require('path');
// Предоставляем определённые API процессу рендеринга
contextBridge.exposeInMainWorld('electronAPI', {
getSystemInfo: () => ipcRenderer.invoke('get-system-info'),
openFile: (filePath) => ipcRenderer.invoke('open-file', filePath),
onSystemEvent: (callback) => ipcRenderer.on('system-event', callback)
});
Представляйте предварительный скрипт как вышибалу в эксклюзивном клубе. Он тщательно решает, что из Node.js может взаимодействовать с вашим UI. Это предотвращает возможность злонамеренного кода захватить возможности вашего приложения.
Шаг 6: Обработка сообщений IPC в главном процессе
Добавьте это в ваш main.js (после настройки приложения):
const { ipcMain } = require('electron');
// Слушаем сообщения IPC от рендеринга
ipcMain.handle('get-system-info', async () => {
return {
platform: process.platform,
arch: process.arch,
cpuCount: require('os').cpus().length,
totalMemory: Math.round(require('os').totalmem() / 1024 / 1024 / 1024) + ' ГБ',
homeDir: require('os').homedir()
};
});
ipcMain.handle('open-file', async (event, filePath) => {
const { shell } = require('electron');
await shell.openPath(filePath);
});
Шаг 7: Процесс рендеринга (Ваш фронтэнд)
Создайте renderer.js:
document.getElementById('btn').addEventListener('click', async () => {
try {
const info = await window.electronAPI.getSystemInfo();
document.getElementById('output').innerHTML = `
<strong>Информация о системе:</strong><br>
Платформа: ${info.platform}<br>
Архитектура: ${info.arch}<br>
Ядра CPU: ${info.cpuCount}<br>
Общая память: ${info.totalMemory}<br>
Домашний каталог: ${info.homeDir}
`;
} catch (error) {
document.getElementById('output').innerHTML = `<span style="color: red;">Ошибка: ${error.message}</span>`;
}
});
Шаг 8: Тестирование вашего приложения
Теперь момент истины:
npm start
Если всё прошло хорошо, вы должны увидеть блестящее окно настольного приложения с работающим приложением. Нажмите на кнопку и полюбуйтесь отображаемой информацией о системе. Вы только что создали настольное приложение! 🎉
Добавление полировки: меню и дополнительные функции
Ваше базовое приложение работает, но оно кажется немного пустым. Давайте добавим родное меню. Добавьте это в ваш main.js:
const { Menu } = require('electron');
function createMenu() {
const template = [
{
label: 'Файл',
submenu: [
{
label: 'Выход',
accelerator: 'CmdOrCtrl+Q',
click: () => {
app.quit();
}
}
]
},
{
label: 'Вид',
submenu: [
{
label: 'Перезагрузить',
accelerator: 'CmdOrCtrl+
