Skip to content

Node.js: desktop-приложения на Electron

Использую Node.js как прикладной runtime для desktop-приложений на базе Electron, системной интеграции, сетевого взаимодействия и packaging-автоматизации.

Node.js может использоваться не как вспомогательная прослойка, а как основа desktop-части приложения:

  • main process приложения и управление жизненным циклом;
  • IPC-взаимодействие между main и renderer;
  • работа с файлами, конфигом и путями ОС;
  • HTTPS/HTTP-запросы к backend-сервису;
  • запуск внешних процессов и сценарии автообновления;
  • build/post-pack скрипты для упаковки приложения под разные ОС.

Что использовал на практике

  • CommonJS-модули через require(...) и модульную организацию Node/Electron-кода;
  • встроенные модули fs, fs/promises, path, os, url, https, child_process, events, process, Buffer;
  • Electron API поверх Node.js runtime: app, BrowserWindow, ipcMain, Tray, Menu, shell, desktopCapturer;
  • файловое хранение пользовательского конфига и восстановление после повреждения config-файла;
  • загрузку и валидацию серверных URL, в том числе через install-time данные и custom URL scheme;
  • сетевое взаимодействие через axios и нативный https;
  • кроссплатформенные сценарии обновления приложения для Windows, Linux, macOS;
  • Node.js-скрипты для post-pack обработки артефактов сборки.

Node.js в desktop-приложении

Основной сценарий в этом проекте - desktop-клиент на Electron, где Node.js обслуживает main process и системные интеграции.

Практически это включает:

  • создание и настройку BrowserWindow;
  • управление single-instance поведением приложения;
  • обработку событий ready, activate, window-all-closed, before-quit, open-url, second-instance;
  • работу с системным меню, tray-иконкой и внешними ссылками;
  • маршрутизацию команд от renderer через ipcMain.handle(...).

Такой опыт важен, потому что в desktop-разработке на Node.js нужно не только "поднять окно", но и корректно управлять состоянием приложения, жизненным циклом и поведением под разные ОС.

IPC и boundary между main / renderer

Организовывал взаимодействие между UI-слоем и Node/Electron-слоем через IPC.

Это выражено через:

  • ipcMain.on(...) и ipcMain.handle(...) в main.js;
  • preload-слой для bridge-логики;
  • явное вынесение системных операций в main process;
  • использование contextIsolation: true у окна приложения.

Через IPC здесь решаются прикладные задачи:

  • получение locale приложения;
  • загрузка URL в окно;
  • открытие внешних ссылок;
  • обновление конфигурации хоста;
  • работа с tray-state и unread-состоянием;
  • запуск update-flow;
  • получение desktop capture sources.

Это хороший практический кейс Node.js как безопасной системной границы, а не только как среды выполнения JavaScript.

Работа с файловой системой и конфигом

Есть опыт использования Node.js для локального хранения и обслуживания состояния приложения.

Что видно в таких сценариях:

  • чтение и запись конфигурации через electron-json-config;
  • работа с файлами через fs и fs/promises;
  • проверка наличия файлов и безопасный fallback;
  • нормализация путей через path.join(...), path.resolve(...), path.basename(...);
  • использование app.getPath('userData') и app.getPath('downloads');
  • восстановление конфигурации при повреждённом config.json.

Отдельно полезен практический сценарий в configFactory.js: при ошибке создания config-объекта код ищет локальный config-файл, сбрасывает его содержимое до пустого JSON и повторно инициализирует конфигурацию. Это типичная production-задача, где Node.js используется для повышения устойчивости desktop-клиента.

URL, protocol handlers и install-time bootstrap

В проекте есть не только обычная конфигурация хоста, но и логика первичного определения серверного URL.

Что использовано:

  • разбор аргументов process.argv;
  • поддержка собственного URL scheme;
  • чтение install-time данных из локального файла;
  • декодирование данных через Buffer.from(..., 'base64');
  • нормализация URL и выделение service-base URL;
  • platform-specific логика для AppImage, macOS и Windows.

Это показывает опыт работы с Node.js в более прикладных сценариях: bootstrap приложения, custom protocol integration и подготовка runtime-конфигурации без ручного ввода пользователем.

Сетевое взаимодействие

Из Node.js-слоя desktop-приложения реализовывал серверное взаимодействие.

Для этого используются:

  • axios для HTTP API-запросов;
  • нативный https для download-flow;
  • https.Agent с кастомными параметрами;
  • валидация доступности и версии backend-сервера;
  • загрузка update-пакетов и серверных данных для bootstrap/update-сценариев.

Из прикладных задач:

  • проверка совместимости серверной версии;
  • запрос конфигурационных данных по токену;
  • получение информации о доступности новой версии приложения;
  • скачивание дистрибутива обновления с показом прогресса.

Это именно тот сценарий, где Node.js в приложении работает как интеграционный слой между desktop-клиентом и backend API.

Процессы ОС и автообновление

Есть опыт использования child_process и системных команд для выполнения платформенно-зависимых операций.

В проекте это выражено через:

  • spawn(...) для запуска внешних процессов;
  • detached-процессы для update-flow;
  • отдельный сценарий для запуска installer-а с повышенными правами на Windows;
  • перемещение/замену бинарника на Linux;
  • запуск .pkg через open на macOS.

Также здесь важен практический аспект Node.js-разработки: один и тот же update-flow приходится адаптировать под разные ОС, ограничения файловой системы и пользовательский runtime-контекст.

Packaging и build automation

Есть опыт использования Node.js не только в runtime, но и в build/publish-цепочке приложения.

Это видно по:

  • webpack.config.js;
  • скриптам в package.json;
  • electron-builder конфигурации;
  • build/scripts/afterPack.js;
  • build/mac/notarize.js.

Практически это включает:

  • post-pack обработку Linux-артефакта;
  • генерацию launcher-скрипта для sandbox-совместимости;
  • файловые операции над собранным executable;
  • platform-specific packaging hooks;
  • использование переменных окружения в build-сценариях.

Такой опыт важен, потому что в реальных Node.js-проектах разработка обычно не ограничивается application-кодом и часто включает automation вокруг сборки и поставки.

Кроссплатформенная специфика

В проекте Node.js-код явно учитывает различия между win32, linux и darwin.

На практике это проявляется в:

  • ветвлении по os.platform() и process.platform;
  • разном поведении update-механизма;
  • различиях в упаковке и post-pack обработке;
  • platform-specific путях и runtime-переменных;
  • отдельных сценариях интеграции с ОС.

Это сильная прикладная часть опыта, потому что кроссплатформенный Node.js-код требует аккуратной работы с файловой системой, процессами, пакетированием и пользовательским окружением.

На чём основан этот раздел

Тезисы выше подтверждаются текущим проектом:

  • основной Node/Electron runtime: main.js;
  • bootstrap и URL-логика: src/js/initConfig.js;
  • конфигурация и recovery config-файла: src/js/configFactory.js, src/js/conf.js;
  • сетевая проверка сервера: src/js/urlChecker.js;
  • tray/menu desktop-логика: src/js/TrayBuilder.js;
  • update-flow и системные процессы: src/js/Updater.js;
  • preload entry и renderer bridge: src/inject/preloadMain.js;
  • build automation: webpack.config.js, build/scripts/afterPack.js, build/mac/notarize.js, package.json.

Что важно в работе с Node.js

На практике считаю ключевыми такие вещи:

  • Node.js особенно силён там, где нужно связать UI, сеть, файловую систему и ОС;
  • desktop-код должен явно разделять renderer и системный слой;
  • файловый и сетевой код нужно писать с учётом recovery/fallback-сценариев;
  • кроссплатформенность надо закладывать в архитектуру сразу;
  • automation и packaging - это такая же часть Node.js-разработки, как и application runtime.

Именно в таком прикладном формате обычно и использую Node.js.

Сайт обновлен и проверен: