Кросс-платформенные приложения на Electron: от концепции до готового дистрибутива
Основной способ: приложение на чистом Electron без фреймворков
Исходная цель - создать минимальное окно браузера, которое работает как настольное приложение. В основе лежит Node.js и Chromium. Установка Electron выполняется через npm.
Как создать окно с загрузкой HTML-страницы?
mkdir my-electron-app
cd my-electron-app
npm init -y
npm install electron --save-dev
Electron js (разработка десктопного приложения на electron)
После установки создаётся файл main.js - точка входа в приложение. В нём импортируется модуль app и BrowserWindow. Создаётся окно с параметрами ширины и высоты, загружается файл index.html.
// main.js
const { app, BrowserWindow } = require('electron');
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
Далее создаётся простой index.html:
<!DOCTYPE html>
<html>
<head><title>Моё приложение</title></head>
<body>
<h1>Hello Electron!</h1>
</body>
</html>
Запуск приложения выполняется командой npx electron .
Типичные ошибки на этом этапе:
- Ошибка "require is not defined" при использовании nodeIntegration: true и contextIsolation: true. Решение - установить nodeIntegration: true и contextIsolation: false, либо использовать preload-скрипты.
- Ошибка "Electron failed to install correctly" - проблемы с правами доступа или архитектурой. Рекомендуется переустановить Electron с флагом --unsafe-perm или использовать npx.
- Окно не отображается - проверяется наличие дисплея и параметры окна, также возможно требуется установить show: true.
Как интегрировать React, чтобы получить реактивную архитектуру?
React используется для построения пользовательского интерфейса. Настройка включает создание проекта React внутри Electron. Один из подходов - использование electron-react-boilerplate или ручная настройка с webpack.
mkdir electron-react-app
cd electron-react-app
npm init -y
npm install react react-dom
npm install --save-dev electron webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin
Создаётся конфигурация webpack и Babel. В main.js загружается index.html, который уже собран webpack. В процессе разработки используется webpack-dev-server или просто сборка.
Как решить проблему двойного скролла или задержки при загрузке?
При использовании React с Electron часто возникает проблема с производительностью из-за множества ререндеров. Рекомендуется использовать React.memo, useMemo и ограничить nodeIntegration. Также при сборке для продакшена следует отключать DevTools.
Как использовать Vue, чтобы упростить шаблонизацию?
Vue.js - альтернатива React. Для интеграции удобно использовать electron-vue (устаревший) или vue-cli-plugin-electron-builder. Современный способ - создать проект Vue через Vite, затем добавить Electron.
npm create vite@latest my-vue-electron -- --template vue
cd my-vue-electron
npm install
npm install electron --save-dev
В корне создаётся electron/main.js. В package.json добавляется скрипт "electron:dev": "concurrently \"vite\" \"wait-on http://localhost:5173 && electron .\"".
Проблема: Vite использует ESM, а Electron работает с CommonJS. Для main.js лучше использовать CommonJS или настроить сборку. Также может возникнуть ошибка CORS при загрузке локальных ресурсов через dev-сервер. Решение - настроить webSecurity: false в окне или использовать file:// протокол.
Как собрать готовое приложение в дистрибутив с помощью electron-builder?
electron-builder - инструмент для упаковки приложения в .exe, .dmg, .deb и другие форматы. Установка: npm install --save-dev electron-builder. В package.json добавляется секция "build": { "appId": "com.example.app", "productName": "MyApp", "directories": { "output": "dist" } }.
npx electron-builder --win --x64
Сборка создаёт установщик в папке dist. Для macOS используется флаг --mac, для Linux --linux.
Ошибка: "Could not find any Electron packages" - нужно указать main файл и убедиться, что electron установлен как зависимость. Также при использовании native модулей требуется пересборка под целевую платформу.
Как использовать TypeScript для повышения надёжности кода?
TypeScript добавляет статическую типизацию. Установка: npm install typescript @types/node @types/electron --save-dev. Создаётся tsconfig.json. Файл main.ts компилируется в main.js. В package.json указывается "main": "dist/main.js". Используется tsc или ts-node для разработки.
// main.ts
import { app, BrowserWindow } from 'electron';
let mainWindow: BrowserWindow | null = null;
app.whenReady().then(() => {
mainWindow = new BrowserWindow({ width: 800, height: 600 });
mainWindow.loadFile('index.html');
});
Проблема: ts-node не работает с Electron из-за различий в модулях. Рекомендуется компилировать отдельно или использовать ts-node с флагом --compiler-options. Альтернатива - electron-forge с поддержкой TypeScript.
Расширенные примеры работы с Electron
Пример 1: IPC для обмена данными между главным и рендерным процессами
IPC (Inter-Process Communication) позволяет передавать сообщения между процессами. В главном процессе регистрируется обработчик, в рендерном вызывается.
// main.js
const { ipcMain, dialog } = require('electron');
ipcMain.handle('open-file', async (event) => {
const result = await dialog.showOpenDialog({ properties: ['openFile'] });
if (result.canceled) return null;
return result.filePaths[0];
});
// renderer.js (в index.html)
const { ipcRenderer } = require('electron');
document.getElementById('btn').addEventListener('click', async () => {
const filePath = await ipcRenderer.invoke('open-file');
console.log('Выбран файл:', filePath);
});
При нажатии кнопки открывается системное диалоговое окно выбора файла. После выбора в консоль выводится путь к файлу.
Пример 2: Системный трей (Tray)
Трей - иконка в системной панели (панели задач). Позволяет управлять приложением без открытого окна.
const { Tray, Menu, nativeImage, app } = require('electron');
let tray = null;
app.whenReady().then(() => {
const icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); // маленькая зелёная точка
tray = new Tray(icon);
const contextMenu = Menu.buildFromTemplate([
{ label: 'Показать окно', click: () => mainWindow.show() },
{ label: 'Выход', click: () => app.quit() }
]);
tray.setToolTip('Моё приложение');
tray.setContextMenu(contextMenu);
});
В системном трее появляется иконка. При клике правой кнопкой мыши отображается меню с опциями.
Пример 3: Автоматическое обновление через electron-updater
Библиотека electron-updater позволяет автоматически загружать и устанавливать обновления из репозитория (например, GitHub Releases).
const { autoUpdater } = require('electron-updater');
autoUpdater.checkForUpdatesAndNotify();
autoUpdater.on('update-available', (info) => {
console.log('Доступно обновление', info.version);
});
autoUpdater.on('download-progress', (progressObj) => {
console.log(`Скорость: ${progressObj.bytesPerSecond}, загружено: ${progressObj.percent}%`);
});
autoUpdater.on('update-downloaded', () => {
autoUpdater.quitAndInstall();
});
При запуске приложение проверяет наличие обновлений на сервере. Если обновление найдено, загружается и после завершения автоматически устанавливается.
Пример 4: Создание меню приложения с акселераторами
Меню приложения можно полностью настроить, добавив горячие клавиши и подменю.
const { Menu, dialog, app } = require('electron');
const menuTemplate = [
{
label: 'Файл',
submenu: [
{
label: 'Открыть',
accelerator: 'CmdOrCtrl+O',
click: () => { dialog.showMessageBox({ message: 'Открытие файла...' }); }
},
{ type: 'separator' },
{ label: 'Выход', role: 'quit' }
]
},
{
label: 'Помощь',
submenu: [
{
label: 'О программе',
click: () => { dialog.showMessageBox({ message: 'Версия 1.0', title: 'О программе' }); }
}
]
}
];
const menu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(menu);
Приложение получает меню с пунктами "Файл" (с подменю "Открыть" и "Выход") и "Помощь" (с подменю "О программе"). Нажатие Ctrl+O (Cmd+O на macOS) вызывает диалоговое окно.