Как собрать electron приложение
Поверите ли вы мне, если я скажу, что настольные приложения Slack , VSCode , Atom , Skype , Discord и Whatsapp , которыми вы сегодня пользуетесь, были написаны с использованием HTML, CSS и JavaScript? Вероятно, нет. Потому что обычно эти языки мы используем только для разработки веб-сайтов.
Но как быть в том случае, если в настольном приложении применяется браузер в виде графического интерфейса ( то, что видит пользователь )? Тогда мы могли бы применять эти языки для визуализации пользовательского интерфейса приложения. Именно этот вариант и действует в указанных выше приложениях. Эти приложения используют скрытый браузер для визуализации пользовательского интерфейса, поэтому для рисования можно использовать HTML и CSS, а для интерактивности — JavaScript.
Хотя проектирование графического интерфейса с использованием HTML, CSS и JavaScript кажется простым, вам все равно нужен мост между собственными системными API и браузером ( в приложении ) для ввода-вывода ( файловая система ), доступа к сети, оборудованию и другим компонентам системы. Без доступа к системным ресурсам наше настольное приложение было бы просто веб-сайтом.
В приложении мы могли бы использовать Node.js, чтобы он действовал как мост между системными ресурсами и браузером. Если код JavaScript, запущенный в браузере, нуждается в доступе к некоторым файлам из системы, он может сделать такой запрос Node.js. Поскольку Node.js может получить доступ к общесистемным ресурсам без каких-либо ограничений, он идеально подходит для работы с бэкендом приложения, без всяких доработок.
Теоретически это похоже на идеальный метод. Но когда дело доходит до реального создания приложения, необходимы познания о разработке собственных настольных приложений, об интеграции с браузером, API-интерфейсах браузера, интеграции Node.js и о многих других вещах. Но не стоит пугаться, ведь у нас есть Electron .
Electron — это инструмент для создания кросс-платформенных настольных приложений с веб-технологиями. Electron использует Node.js для бэкенда приложения и браузер Chromium для фронтенда. Мы можем написать графический интерфейс приложения с помощью HTML, CSS и JavaScript. Electron обеспечивает интеграцию между JavaScript, работающим в браузере, и JavaScript, работающим в Node.js.
На самом деле, указанные выше приложения созданы с помощью Electron . Он имеет огромное сообщество, множество сторонних модулей, большинство компаний полагаются на него в своих настольных приложениях. Вот список таких приложений. В нем вы также можете найти Twitch , Zeplin и WebTorrent .
Подобно Electron, для создания настольных приложений вы также можете применять NW.js . Я лично не считаю, что с NW.js комфортно работать. А чтобы узнать различия между этими двумя инструментами, вы можете ознакомиться с этой документацией.
Архитектура Electron
Electron использует многопроцессорную архитектуру для управления состоянием приложения и пользовательским интерфейсом. Процесс main контролирует состояние приложения, а процесс renderer управляет пользовательским интерфейсом. Для выполнения насыщенных графикой задач Electron использует процесс GPU , но это опционально.
При запуске приложения Electron создается процесс main , который для каждого приложения может быть только один. Он может взаимодействовать с собственными системными API и запускать процессы renderer . Процесс renderer отвечает за отображение пользовательского интерфейса с HTML, CSS и JavaScript.
Точкой входа в приложение Electron является файл JavaScript ( назовем его main.js ), который выполняется внутри процесса main . Процесс main имеет доступ по умолчанию к API Node.js, но не к API Chromium. Поэтому внутри вы можете использовать любой API Node.js, например fs.writeFile () или require () , но не document или window.addEventListener () .
Приложение на основе Electron — это нечто похожее на браузер. Процесс main похож на браузер, а процессы renderer похожи на вкладки браузера. Процесс main может открывать столько вкладок браузера, сколько возможно процессов renderer . В среде Electron мы называем вкладку window , поскольку это буквально окно приложения, как показано ниже.
Из файла main.js ( процесс main ) мы создаем окно ( как вкладку с нашей предыдущей аналогией ), создавая экземпляр класса BrowserWindow , предоставленный пакетом electron . Этот экземпляр создает окно приложения, но по умолчанию оно будет пустым.
Пакет electron предоставляет связанные с Electron модули (например, BrowserWindow ) и модули системного API высокого уровня (например, notification , dialog , touch bar и т. д.). Модули, предоставляемые этим пакетом, доступны как в процессе main , так и в процессе renderer . Но не все модули, предоставляемые этим пакетом, являются доступными в этих процессах (подробнее об этом позже).
Мы загружаем HTML-страницу внутри этого окна ( win ), вызывая метод win. loadFile ( path ) или win. loadURL ( url ). После Electron создает процесс renderer и отображает веб-страницу из локального файла или удаленного URL-адреса, который также может использовать протокол file: // .
Если кратко, JavaScript, выполняемый в основном процессе main , является координатором всего приложения, но он не может отображать пользовательский интерфейс. Для этого необходимо создать процесс renderer через интерфейс BrowserWindow .
BrowserWindow — это просто интерфейс высокого уровня для отображения и управления веб-страницей, но сам он не может отображать веб-страницы. Интерфейс webContent — это низкоуровневый API, который отвечает за визуализацию и управление веб-страницей с помощью процесса визуализации Chromium.
Процесс renderer — это процесс операционной системы, связанный с интерфейсом webContents . Вы можете получить доступ к интерфейсу webContents из интерфейса BrowserWindow , используя свойство win. webContents . Чтобы получить PID ОС, примените метод win.webContents. getOSProcessId (), а для получения PID рендеринга Chromium примените метод win.webContents. getProcessId () .
Поскольку BrowserWindow — это просто высокоуровневый интерфейс для интерфейса webContents , вы можете вызвать win.webContents.loadFile () вместо win.loadFile () для рендеринга HTML-страницы внутри окна.
На первый взгляд, на каждое окно приходится один процесс renderer , но это не всегда так. Процесс renderer создается тогда, когда мы загружаем веб-страницу внутри окна. Окно может порождать обработку другим renderer с помощью тега HTML < webview >, предоставленного Electron, или добавляя объект BrowserView в существующее окно.
Процесс Main против Renderer
Совершенно очевидно, что процесс main управляет состоянием приложения, а процессы renderer управляют пользовательским интерфейсом приложения. Хотя, есть несколько элементов, к которым процесс renderer не может иметь доступ.
По умолчанию, процесс main имеет доступ к API Node.js. При создании процесса renderer через new BrowserWindow ( options ) мы можем указать, должен ли процесс renderer также иметь доступ к API-интерфейсам Node.js. Это контролируется свойством options.webPreferences. nodeIntegration .
Значение этого свойства по умолчанию — false , поэтому нам нужно установить его в true , если мы хотим, чтобы JavaScript, работающий внутри процесса renderer , имел доступ к таким API-интерфейсам Node.js, как fs.writeFile () или require () .
Причина, по которой Electron не предоставляет доступ к API-интерфейсам Node.js из процессов renderer по умолчанию, заключается в том, что вредоносный сторонний код JavaScript, например сторонняя библиотека, может получить доступ к системе пользователя, вызвав API-интерфейсы Node. Поэтому будьте осторожны.
Кроме того, вы не можете создать окно браузера из другого окна. Это означает, что JavaScript, выполняющийся внутри процесса renderer , не может создать экземпляр new BrowserWindow ( options ) для создания нового окна. Создание окон должно выполняться процессом main .
Однако вызов window.open () создаст другое окно, создав экземпляр класса BrowserWindow , который запустит процесс renderer . Но это окно имеет ограниченную функциональность, как описано здесь .
Еще одно отличие состоит в том, что все собственные системные API ( внешние для Node.js ) доступны только из процесса main . Например, если вы хотите открыть системный диалог, то можете использовать модуль dialog внутри JavaScript, запущенного в процессе main , а не внутри окна ( процесс renderer ).
Есть несколько модулей, доступных из процессов main и renderer . Ниже их список вместе с API. Документацию по каждому модулю вы можете найти на этой странице.
Взаимодействие между процессами
Например, как мы можем открыть другое окно приложения, создав экземпляр класса BrowserWindow ? Допустим пользователь нажимает в окне на элемент <button> , чтобы увидеть изображение с элементами выбора масштаба. Именно здесь на первый план выходит межпроцессная коммуникация ( IPC ).
Эти коммуникации могут происходить синхронно или асинхронно в зависимости от методов модуля.
Фоновые задания
Если вы хотите выполнить задачу, интенсивно использующую ЦП, то вам не нужно запускать внутри процесса рендеринга код JavaScript с длительным исполнением, который заблокировал бы намертво пользовательский интерфейс на несколько секунд или минут. Однако, если вы это сделаете, предположим, случайно, тогда другие окна не будут затронуты, поскольку они выполняются в отдельных процессах renderer .
Но все же блокировка пользовательского интерфейса нежелательна, поскольку это плохо сказывается на взаимодействии с пользователем. Что хорошего в таком приложении, если пользователь не может взаимодействовать с пользовательским интерфейсом? Можно сказать, давайте использовать процессы main , поскольку они не связаны с renderer , но, к сожалению, блокировка main приведет к тому, что также не станет работать и ваше приложение ( и все его окна ).
Но чтобы выполнять фоновые задания, не нужно изобретать колесо. Все-таки, у нас есть несколько хитростей в запасе. Для запуска фоновой задачи мы можем использовать API WebWorker из JavaScript, запущенный внутри процесса renderer . Мы также могли бы использовать встроенный модуль Node.js worker_threads для запуска рабочего потока точно так же, как потока WebWorker .
Для выполнения фоновых и ресурсоемких задач некоторые специалисты могут предложить окна frameless transparent , которые пользователи не видят. Однако, когда есть способы получше, такик уловки следует избегать.
Веб-воркер не имеет автоматического доступа к API Node.js. При создании объекта BrowswerWindow , нам нужно установить значение true для свойства options.webPreferences.nodeIntegrationInWorker . Это свойство работает независимо от свойства nodeIntegration .
Хотя мы можем получить доступ ко всем API-интерфейсам Node.js внутри веб-воркера, получить доступ к собственным API-интерфейсам Electron невозможно. Для получения дополнительной информации о многопоточности в Electron прочтите эту документацию.
Общее описание
Все, что мы обсуждали до сих пор — это просто обзор архитектуры Electron. А для тех, кто хочет знать больше, можно почитать вот эту документацию . Подведем итог проведенному обсуждению с помощью упрощенной диаграммы.
Можно ли, используя HTML, CSS и JavaScript, создавать настольные приложения? Автор статьи, перевод которой мы сегодня публикуем, даёт утвердительный ответ на этот вопрос. Здесь он расскажет о том, как, применяя веб-технологии и пользуясь возможностями фреймворка Electron, создавать кроссплатформенные приложения для настольных операционных систем.
Electron
Electron — это фреймворк для разработки настольных приложений с использованием HTML, CSS и JavaScript. Такие приложения могут работать на различных платформах. Среди них — Windows, Mac и Linux.
В основе Electron лежат проекты Chromium и Node.js, объединённые в единую среду, обеспечивающую работу приложений. Это даёт возможность применять веб-технологии при разработке настольных программ.
Electron — серьёзный проект, который использован при создании множества популярных приложений. Среди них — мессенджеры Skype и Discord, редакторы для кода Visual Studio Code и Atom, а также — ещё более 700 приложений, сведения о которых опубликованы на сайте Electron.
Electron Forge
Для разработки приложения с использованием Electron этот фреймворк надо настроить. Это касается и тех случаев, когда в приложении планируется применять другие фреймворки или библиотеки, например — Angular, React, Vue, или что-то другое.
Инструмент командной строки Electron Forge позволяет серьёзно упростить процесс настройки Electron. Он даёт в распоряжение разработчика шаблоны приложений, основанных на Angular, React, Vue, и на других фреймворках. Это избавляет программиста от необходимости настраивать всё вручную.
Кроме того, Electron Forge упрощает сборку и упаковку приложения. На самом деле, это средство обладает и многими другими полезными возможностями, узнать о которых можно из его документации.
Рассмотрим процесс разработки простого приложения на Electron с использованием Electron Forge.
Предварительная подготовка
Для того чтобы приступить к разработке Electron-приложений с использованием Electron Forge вам понадобится система с установленной платформой Node.js. Загрузить её можно здесь.
Для глобальной установки Electron Forge можно воспользоваться следующей командой:
Создание шаблонного приложения
Для того чтобы создать шаблонное приложение с использованием Electron Forge выполним следующую команду:
Эта команда инициализирует новый проект приложения, имя которого — simple-desktop-app-electronjs . На выполнение этой команды понадобится некоторое время. После того, как шаблонное приложение будет создано, запустить его можно так:
Здесь мы переходим в его папку и вызываем соответствующий npm-скрипт.
После этого должно открыться окно, содержимое которого похоже на то, что показано на следующем рисунке.
Окно приложения, созданного средствами Electron Forge
Поговорим о том, как устроено это приложение.
Структура шаблонного приложения
Материалы, из которых состоит шаблонное приложение, создаваемое средствами Electron Forge, представлены набором файлов и папок. Рассмотрим важнейшие составные части приложения.
▍Файл package.json
Этот файл содержит сведения о создаваемом приложении, о его зависимостях. В нём имеется описание нескольких скриптов, один из которых, start , использовался для запуска приложения. Новые скрипты в этот файл можно добавлять и самостоятельно.
В разделе файла config.forge можно найти специфические настройки для Electron. Например, раздел make_targets содержит подразделы, описывающие цели сборки проекта для платформ Windows ( win32 ), Mac ( darwin ) и Linux ( linux ).
В package.json можно найти и запись следующего содержания: "main": "src/index.js" , которая указывает на то, что точкой входа в приложение является файл, расположенный по адресу src/index.js .
▍Файл src/index.js
В соответствии со сведениями, находящимися в package.json , основным скриптом приложения является index.js . Процесс, который выполняет этот скрипт, называется основным процессом (main process). Этот процесс управляет приложением. Он используется при формировании интерфейса приложения, в основе которого лежат возможности браузера. На нём же лежит ответственность за взаимодействие с операционной системой. Интерфейс приложения представлен веб-страницами. За вывод веб-страниц и за выполнение их кода отвечает процесс рендеринга (renderer process).
▍Основной процесс и процесс рендеринга
Цель основного процесса заключается в создании окон браузера с использованием экземпляра объекта BrowserWindow . Этот объект использует процесс рендеринга для организации работы веб-страниц.
У каждого Electron-приложения может быть лишь один основной процесс, но процессов рендеринга может быть несколько. Кроме того, можно наладить взаимодействие между основным процессом и процессами рендеринга, об этом мы, правда, здесь говорить не будем. Вот схема архитектуры приложения, основанного на Electron, на которой представлен основной процесс и два процесса рендеринга.
Архитектура Electron-приложения
На этой схеме показаны две веб-страницы — index.html и abcd.html . В нашем примере будет использоваться лишь одна страница, представленная файлом index.html .
▍Файл src/index.html
Скрипт из index.js загружает файл index.html в новый экземпляр BrowserWindow . Если описать этот процесс простыми словами, то оказывается, что index.js создаёт новое окно браузера и загружает в него страницу, описанную в файле index.html . Эта страница выполняется в собственном процессе рендеринга.
▍Разбор кода файла index.js
Код файла index.js хорошо прокомментирован. Рассмотрим его важнейшие части. Так, следующий фрагмент кода функции createWindow() создаёт экземпляр объекта BrowserWindow , загружает в окно, представленное этим объектом, файл index.html и открывает инструменты разработчика.
В готовом приложении строку кода, открывающую инструменты разработчика, имеет смысл закомментировать.
В коде этого файла часто встречается объект app . Например — в следующем фрагменте:
Объект app используется для управления жизненным циклом приложения. В данном случае после завершения инициализации Electron вызывается функция, ответственная за создание окна приложения.
Объект app используется и для выполнения других действий при возникновении различных событий. Например, с его помощью можно организовать выполнение неких операций перед закрытием приложения.
Теперь, когда мы ознакомились со структурой Electron-приложения, рассмотрим пример разработки такого приложения.
Разработка настольного приложения — конвертера температур
В качестве основы для этого учебного приложения воспользуемся ранее созданным шаблонным проектом simple-desktop-app-electronjs .
Для начала установим пакет Bootstrap, воспользовавшись, в папке проекта, следующей командой:
Теперь заменим код файла index.html на следующий:
Вот как работает этот код:
- Здесь создаётся текстовое поле с идентификатором celcius . Когда пользователь вводит в это поле некое значение, которое должно представлять собой температуру в градусах Цельсия, вызывается функция celciusToFahrenheit() .
- Текстовое поле с идентификатором fahrenheit , также создаваемое в этом коде, принимает данные от пользователя, которые должны представлять собой температуру в градусах Фаренгейта, после чего вызывается функция fahrenheitToCelcius() .
- Функция celciusToFahrenheit() конвертирует температуру, выраженную в градусах Цельсия и введённую в поле celcius , в температуру в градусах Фаренгейта, после чего выводит то, что у неё получилось, в поле fahrenheit .
- Функция fahrenheitToCelcius() выполняет обратное преобразование — берёт значение температуры, выраженное в градусах Фаренгейта и введённое в поле fahrenheit , преобразует его в значение, выраженное в градусах Цельсия, после чего записывает то, что у неё получилось, в поле сelcius .
Как видите, каждая из этих функций получат значение соответствующего поля страницы, выполняет преобразование полученного значения и записывает то, что получилось, в другое поле. Функции это очень простые, в частности, значения, с которыми они работают, никак не проверяются, но в нашем случае это неважно.
Будем считать, что приложение готово. Испытаем его.
Запуск приложения
Для того чтобы запустить приложение, воспользуемся следующей командой:
После её успешного выполнения будет открыто окно приложения со следующим содержимым.
Окно приложения-конвертера
Поэкспериментируйте с приложением, вводя в поля различные значения.
Теперь, когда мы убедились в том, что приложение работает так, как ожидается, пришло время его упаковать.
Упаковка приложения
Для того чтобы упаковать приложение, воспользуйтесь следующей командой:
На выполнение этой команды системе понадобится некоторое время. После того, как её работа завершится, загляните в папку out , которая появится в папке проекта.
Эксперимент по разработке Electron-приложения, описанный здесь, проводился на компьютере, работающем под управлением ОС Windows. Поэтому в папке out была создана папка simple-desktop-app-electronjs-win32-x64 . В этой папке, кроме прочего, можно найти .exe -файл приложения. В нашем случае он называется simple-desktop-app-electronjs.exe . Для запуска приложения достаточно обычного двойного щелчка мышью по этому файлу.
Разберём имя папки, в которую попал исполняемый файл приложения. А именно, он построен по шаблону имя приложения - платформа - архитектура . В нашем случае его структура раскрывается так:
- Имя приложения — simple-desktop-app-electronjs .
- Платформа — win32 .
- Архитектура — x64 .
Предположим, вам нужно упаковать приложение для какой-то другой платформы и архитектуры. Для этого можно воспользоваться расширенным вариантом вышеописанной команды. Структура этой команды выглядит так:
Например, для того чтобы сформировать пакет приложения для Linux, можно воспользоваться следующей командой:
После завершения её работы в папке проекта out появится директория simple-desktop-app-electronjs-linux-x64 с соответствующим содержимым.
Создание установочных файлов приложений
Для того чтобы создать установочный файл приложения воспользуйтесь следующей командой:
Результаты её работы окажутся в уже знакомой вам папке out . А именно, запуск этой команды в вышеприведённом виде на Windows-машине приведёт к созданию установочного файла приложения для Windows в папке out\make\squirrel.windows\x64 . Как и команда package , команда make , вызванная без параметров, создаёт установщик для платформы, используемой при разработке.
Итоги
В этом материале мы рассмотрели основы архитектуры Electron-приложений и написали простую программу. Если вы подумывали о том, чтобы разработать собственное приложение, основанное на Electron, теперь у вас есть базовые знания, самостоятельно расширив и дополнив которые, вы сможете создать то, что вам хочется.
Это руководство проведёт вас через процесс создания простого Hello World приложения в Electron, похожий на electron/electron-quick-start .
К концу этого урока ваше приложение откроет окно браузера, отображая веб-страницу с информацией о том, какие версии Chromium.js Node и Electron работают.
Prerequisites
Чтобы использовать Electron вы должны установить Node.js. Мы рекомендуем Вам использовать последнюю доступную LTS версию.
Пожалуйста, установите Node.js с помощью предварительно собранных установщиков для вашей платформы. В противном случае могут возникнуть проблемы совместимости.
Чтобы убедится что Node.js был установлен правильно, напишите следующие команды в терминале:
Команды должны вывести версии Node.js и npm соответственно.
Note:Так как Electron встраивает Node.js в двоичный код, выполняемая версия Node.js может отличатся.
Создание приложения
Сборка приложения
Приложения Electron имеют ту же общую структуру, что и другие проекты Node.js. Начните с создания папки и инициализации пакета npm.
Команда init запросит некоторые значения для файла конфигурации. В этом туториале стоит придерживаться следующего:
- Значение entry point должно быть main.js .
- Поля author и description могут быть любыми, но необходимы для создания пакета.
Ваш package.json файл должен выглядеть примерно так:
Далее установите пакет electron как devDependencies .
Примечание: Если у вас возникли какие-либо проблемы с установкой Electron, пожалуйста, обратитесь к руководству Advanced Installation.
Наконец, чтобы стал возможен запуск приложения, добавьте команду start в разделе scripts файла package.json , как показано далее:
Эта start команда откроет ваше приложение в режиме разработчика.
Примечание: Эта команда запускает приложение из корневой папки. На этом шаге возможна ошибка, которая заключается в том, что не найдено приложение для запуска.
Запуск main process
В процессе выполнения, Electron будет искать этот скрипт в основном поле вашего package.json конфига, который вы сконфигурировали в процессе формирования кода приложения.
Чтобы инициализировать основной скрипт, создайте пустой файл с именем main.js в корневой папке вашего проекта.
Примечание: Если вы снова запустите скрипт запуска на этот момент, ваше приложение больше не будет выявлять никаких ошибок! Тем не менее, он не будет делать ничего, потому что мы не добавили код в main.js .
Создание веб-страницы
Прежде чем мы сможем создать окно для нашего приложения, нам нужно создать контент, который будет загружен в него. В Electron каждое окно отображает веб-содержимое, которое может быть загружено из локального HTML файла или удаленного URL.
В этом туториале вы будете создавать первое. Создайте index.html файл в корневой папке проекта:
Замечание: Посмотрев на этот HTML-документ, можно заметить, что версии не указаны в блоке body. Мы вручную вставим их позже с помощью JavaScript.
Открытие веб-страницы в окне браузера
Because the main process runs Node.js, you can import these as CommonJS modules at the top of your file:
Then, add a createWindow() function that loads index.html into a new BrowserWindow instance.
Next, call this createWindow() function to open your window.
Note: At this point, your Electron application should successfully open a window that displays your web page!
Quit the app when all windows are closed (Windows & Linux)
On Windows and Linux, exiting all windows generally quits an application entirely.
Open a window if none are open (macOS)
Whereas Linux and Windows apps quit when they have no windows open, macOS apps generally continue running even without any windows open, and activating the app when no windows are available should open a new one.
Because windows cannot be created before the ready event, you should only listen for activate events after your app is initialized. Do this by attaching your event listener from within your existing whenReady() callback.
Note: At this point, your window controls should be fully functional!
Access Node.js from the renderer with a preload script
Now, the last thing to do is print out the version numbers for Electron and its dependencies onto your web page.
Note: If you need a more in-depth look at Electron processes, see the Process Model document.
This is where attaching a preload script to your renderer comes in handy. A preload script runs before the renderer process is loaded, and has access to both renderer globals (e.g. window and document ) and a Node.js environment.
Create a new script named preload.js as such:
The above code accesses the Node.js process.versions object and runs a basic replaceText helper function to insert the version numbers into the HTML document.
To attach this script to your renderer process, pass in the path to your preload script to the webPreferences.preload option in your existing BrowserWindow constructor.
We use a path relative to the currently executing JavaScript file so that your relative path will work in both development and packaged mode.
Bonus: Add functionality to your web contents
At this point, you might be wondering how to add more functionality to your application.
The code contained in renderer.js can then use the same JavaScript APIs and tooling you use for typical front-end development, such as using webpack to bundle and minify your code or React to manage your user interfaces.
Recap
After following the above steps, you should have a fully functional Electron application that looks like this:
Около года назад на Canonium вышла статья, в которой рассказывалось о построении node-webkit приложения. Эта статья стала одной из самых популярных у меня в блоге и даже пару раз мелькала в крупных пабликах в ВК, приводя всё больше и больше читателей.
С того времени изменилось многое: от Node.js отделился io.js, node-webkit сменил имя на nw.js, GitHub выпустил стабильную версию своего редактора кода Atom, а вскоре случилось явление Electron широкой публике.
Если говорить кратко, то Electron — это альтернатива NW.js, представляющая собой среду выполнения для построения настольных приложений, написанных, разумеется, на JavaScript.
Нужно заметить, что Electron предоставляет практически равные с NW.js возможности, кроме некоторых особенностей, о которых в рамках этой серии статей я говорить не буду. Следует сказать, что Electron обладает более сдержанной и качественной документацией, которую хочется читать, в отличие от того же NW.js.
Основные отличия
Далее Electron я буду называть «Электроном».
Ни для кого не секрет, что io.js вернулся в состав Node.js, который теперь регулируется Linux Foundation. Дело в том, что io.js сыграл злую шутку с NW.js, поманив его создателя на свою сторону. Создатели Электрона тоже не оставались в стороне, но, к счастью, уже успели вернуться на Node.js и успешно его поддерживают, в то время как NW.js 12-ой и 13-ой версии всё ещё базируются на io.js, причем не первой свежести.
В NW.js главный файл — это html-файл, указанный в package.json , в то же время в Электроне главным файлом является сценарий, написанный на JavaScript. Это позволяет писать приложения, скажем так, на более низком уровне, не прибегая лишний раз к скриптам в самом браузере. На самом деле, говорить так не совсем корректно, но таким образом упрощается маршрутизация по страницам внутри приложения. Как говорится в документации, в какой-то мере Электрон здесь представляет собой подобие Node.js.
GitHub создал Atom. Вместе с Atom родился Atom Shell. Atom Shell переродился в Электрон. В этой небольшой цепочке событий есть ключевое слово — GitHub. Да, Intel поддерживает NW.js, да, NW.js медленно, но развивается. Однако, GitHub будет поддерживать свою разработку столько, сколько будет существовать редактор Atom.
На самом деле, это не все отличия Электрона от NW.js, есть и другие — более технические. С полным списком можно ознакомиться в документации проекта.
Принцип работы
Принцип работы Электрона основан на двух типах процессов:
Первый тип — основной процесс, который отвечает за интеграцию и взаимодействие с GUI операционной системы. Под этим понятием скрывается интеграция в док на OS X или панель задач на Windows, а также сворачивание в трей, полноэкранный режим и прочие обыденные и нативные для ОС штуки. Такой процесс может быть запущен только один раз на всю жизнь приложения.
Второй тип — процесс рендеринга, отвечающий за отображение окна браузера, в котором с помощью одной магической строчки может быть открыта страница приложения или любая другая веб-страница. Таких процессов может быть произвольное число. За создание процесса рендеринга отвечает основной процесс.
Для того, чтобы породить основной процесс используется следующая схема рождения приложения:
- Электрон читает package.json и ищет в нём секцию main, в которой определен основной файл приложения. Этот файл далее в статье я буду называть «точкой входа».
- Затем происходит обработка «точки входа» и создаётся основной процесс, который в свою очередь, при желании разработчика, открывает какую-либо страницу или страницы, то есть создаёт окно браузера. А если говорить точнее, то порождает процесс или процессы рендеринга.
Если попытаться графически изобразить жизнь приложения, построенного на Электроне, то она будет иметь следующий вид:
Возможности Electron
Перед тем, как приступить к написанию js-файла, который будет выступать в роли точки входа для всего приложения, необходимо взглянуть на доступный разработчику API (набор модулей), чтобы позднее можно было ссылаться на модуль без приведения его описания.
Для компактности статьи я вынес описание доступных API Электрона версии 0.33.3 в отдельный Gist.
Настройка окружения
Думаю, не стоит упоминать, что для работы с Электроном вам нужен Node.js и пакетный менеджер npm актуальной версии. Кроме этого, я рекомендую глобально установить пакет electron-prebuilt, который позволит автоматически загружать актуальную версию Электрона и запускать приложения без необходимости предварительной сборки.
После установки пакет автоматически загрузит текущую стабильную версию Электрона. Теперь, для того, чтобы запустить приложение, необходимо всего лишь выполнить команду electron . в директории проекта. Для последующей автоматизации процесса разработки я советую добавить эту команду в секцию скриптов в package.json :
Эта запись даст возможность инициировать запуск приложения по команде npm start .
При желании можно загружать последнюю или любую другую версию Электрона вручную. Подробнее об этом написано в документации.
К слову, вы можете установить этот пакет локально, но в этом случае команда electron . преобразуется в страшный и некрасивый набор символов:
Кроме самого Электрона я также советую установить пакет XO, который является оберткой над ESLint:
ESLint является самым передовым линтером js-кода, разрабатываемый Николасом Закасом.
Настройка WebStorm
Сначала необходимо перейти к настройке библиотек и фреймворков и, после этого, выбрать там наш любимый JavaScript:
Нажимаем кнопку Download и выбираем слева вверху канал пакетов TypeScript community stubs. Затем ищем в большом списке всякой всячины запись github-electron, выбираем её и кликаем на кнопку Download and install. Готово!
Подсказка
Для поиска по списку кликните на любом элементе списка и начните вводить интересующее вас слово.
Первое приложение
Первым шагом в начале разработки любого Node.js приложения будет создание файла package.json . Вы можете создать его в полуавтоматическом режиме с помощью команды npm init , отвечая на вопросы, или же вручную, добавив лишь самое нужное:
Так как я ещё не решил, что мы будем разрабатывать в течении всей серии статей, пока что приложение будет иметь имя app.
Теперь самое время выполнить команду, добавляющую в package.json поддержу js-линтера XO:
Эта команда автоматически добавит в package.json всё самое необходимое, а также установит локальную копию XO. Остаётся лишь добавить вызов XO в скрипт start, чтобы перед запуском приложения, написанный ранее js-код, всегда оставался чистым и хорошо пахнул:
Я также добавил и изменил несколько правил проверки кода, чтобы линтер соответствовал моим личным требованиям и был удобен в использовании.
Самое время создать какой-нибудь простенький html-файл, который в последствии будет загружаться при старте приложения. Как мне кажется, нет ничего лучше, чем вывести на экран версию Node.js, Electron и Chrome. Для этого обратимся к модулю process, который был расширен Electron. Теперь, помимо информации о текущем процессе, он также может предоставлять информацию о типе процесса (основной или рендер), версию Chrome и Electron, а также путь до исполняемого js-файла.
Забыл сказать, что при написании приложения я буду по возможности и желанию использовать некоторые фишки из ES2015 (ES6).
Файл main.js является «точкой входа» для всего приложения. В нём будут создаваться окна и обрабатываться системные события.
Сначала необходимо подключить модуль app, отвечающий за управление жизненным циклом приложения и browser-window, создающий новое окно браузера.
Далее создаётся ссылка на объект Window. Это делается для того, чтобы окно не закрывалось автоматически, когда объект будет обработан сборщиком мусора.
При закрытии всех окон приложения следует из него выйти. В OS X это событие является общим для приложений и их баров меню, поэтому здесь присутствует условие, отбрасывающее эту платформу.
После того, как Электрон полностью будет инициализирован, станет доступным API управления приложением. Ниже представлен код, который создаёт новое окно браузера размерами 800 на 600 пикселей. Затем в этом окне загружается ранее созданный нами html-файл.
Важно заметить, что даже если вы не загрузите ни один из html-файлов, процесс рендеринга всё равно будет запущен, так как ранее уже было создано окно браузера.
В конце вешается обработчик события closed, которое всплывает тогда, когда окно браузера уже было закрыто. После того, как вы получили данное событие, необходимо удалить ссылку на окно и больше его не использовать.
К слову, не стоит путать событие closed с похожим на него событием close, которое посылается, когда окно будет закрыто, то есть перед closed.
Вообще, тема событий в Электроне достойна отдельной статьи, но в силу моей лени, желающие могут обратиться к документации. Скажу лишь, что жизненный цикл приложения в событиях будет выглядеть следующим образом:
- will-finish-launching
- ready
- browser-window-created
- page-title-updated
- close
- before-quit
- will-quit
- quit
- window-all-closed
- closed
События, событиями, но вернемся к нашему приложению — самое время запустить его, используя команду npm start .
В итоге мы имеем окно, в котором отображается текущая версия Node.js, Electron и Chrome. Кроме того, окно приложениия имеет служебное меню с небольшим набором стандартных пунктов. Служебным оно называется из-за того, что после сборки проекта, как вы увидите позднее, оно исчезает.
Распространение приложения
Для сборки приложения я предлагаю воспользоваться пакетом electron-packager. Сначала установим его глобально:
В этот раз мы обойдемся без планировщика задач, наподобие Grunt или Gulp. Мы же взрослые люди? — думаю, да!
Просто создадим новый скрипт build в package.json с таким содержанием:
Теперь, выполнив команду npm run build вы получите сборку своего приложения под операционную систему Windows. Если же вам необходима сборка под все три платформы, то команда будет иметь вид:
После сборки приложения под все три платформы будет создано, как это ни странно, пять директорий:
- app-darwin-x64
- app-linux-ia32
- app-linux-x64
- app-win32-ia32
- app-win32-x64
Но самое забавное, что полностью собранный «комплект» весит всего лишь каких-то жалких 500Мб.
Кроме явного указания имени приложения и версии Электрона в команде, можно воспользоваться данными из package.json . Создадим два поля, которые будут содержать имя публикуемого приложения и версию, с помощью которой необходимо будет собрать его:
После этого в команде станут доступны переменные:
- $npm_package_publishName
- $npm_package_electronVersion
Разумеется, что вам никто не запрещает использовать поле name как имя приложения:
- $npm_package_name
- $npm_package_version
В итоге команда может принять вид:
К сожалению, на Windows я так и не смог заставить electron-packager использовать $npm_package_* . Зато на OS X это замечательно работает.
Сейчас я предлагаю немного подробнее остановиться на аргументах, передаваемых в пакет electron-packager . Шаблон команды выглядит следующим образом:
Доступные для пользователя аргументы:
Обязательные
- platform — платформа ( all или win32 , linux , darwin )
- arch — разрядность ( all или ia32 , x64 )
- version — версия Электрона для сборки
Опциональные
- all — эквивалент --platform=all --arch=all
- out — директория, в которую будут помещены сборки
- icon — иконка приложения ( .icns или .ico )
- app-bundle-id — идентификатор приложения в plist
- app-version — версия приложения
- build-version — версия сборки приложения для OS X
- cache — директория, в которой будет располагаться кэш приложения
- helper-bundle-id — идентификатор приложения для помощника plist
- ignore — исключение файлов из сборки
- prune — запуск команды npm prune --production в приложении
- overwrite — перезапись уже созданных сборок
- asar — упаковка исходников приложения в asar-архив
- asar-unpack — распаковка указанных файлов в директорию app.asar.unpacked
- sign — идентификатор для входа в codesign (OS X)
- version-string — ключи для сборки (Windows). Список ключей смотрите в документации пакета
О том, как добавлять иконки, что вообще следует делать перед распространением приложения и как создать установщик для сборки, я расскажу в заключительной части этой серии статей.
Список литературы
По традиции оставляю ссылки на то, что можно почитать, чтобы расширить свой кругозор в рамках этой статьи. На русском языке ничего нет, так как у нас Электрон как-то не особо популярен.
Статьи
Модули
Делимся на оплату хостинга или кофе.
Чем чаще пью кофе, тем чаще пишу статьи.
Если вы занимаетесь веб-разработками, то, вероятно, наслышаны об Electron. Для тех же, кто не в курсе, скажу, что это достаточно противоречивый фреймворк для создания приложений, совместимых с Windows, macOS и Linux, на основе веб-технологий и единой базы кода. Несмотря на то, что его приложения могут уступать нативным в скорости и легковесности, Electron позволяет веб-разработчикам развертывать их на 3 главных PC платформах, а, значит, экономит наше время и деньги. Фактически ряд широко распространенных настольных приложений, включая Visual Studio Code, Slack и Discord, созданы с помощью Electron.
В данном руководстве мы создадим простое приложение Electron. Предварительно вам необходимо ознакомиться с Node.js, лежащей в основе рассматриваемого фреймворка. Помимо этого не обойтись без первоначальных знаний о библиотеке Express. И в качестве бонуса используем TypeScript вместо JavaScript, после чего вы, вряд ли, захотите вернуться к JS.
При желании можете обратиться к моему репозиторию за более подробным материалом о приложении Electron с фронтендом Angular.
Введение
По сути, приложения Electron работают по той же фронтенд/бэкенд модели, что и большинство веб-приложений. Отличие же в том, что фронтенд-часть выполняется не в браузере, а в своем отдельном окне, при этом бэкенд-компонент является приложением Node, выполняющимся локально, а не на сервере.
Процесс создания приложения можно разбить на несколько основных этапов:
- Настройка среды
- Настройка TypeScript
- Создание бэкенда
- Создание фронтенда
- Тестирование приложения
- Сборка приложения
О безопасности: внашем примере для обеспечения взаимодействия фронтенда и бэкенда послужит сервер Express, что позволит нам оптимизировать процесс разработки и легко перенести в Electron уже имеющиеся у вас веб-приложения. Однако в производственной среде с этой целью всегда применяется Electron IPC.
1. Настройка среды
Сначала убедитесь, что на вашем компьютере установлен Node.
Затем создайте новый каталог для приложения Electron и, запустив терминал, перейдите в него. Теперь для инициализации нового проекта Node выполните npm init . Следуйте указаниям, выбирая варианты по умолчанию, если не уверены в ответе.
Примечание: по желанию на данном этапе вы также можете настроить систему контроля версий Git. Сделав это, убедитесь, что она игнорирует папки /dist и /build , поскольку в них будет находиться транслированный код и скомпилированные исполняемые файлы.
Установка зависимостей
Для установки необходимых зависимостей выполните из корневого каталога проекта следующие команды:
2. Настройка TypeScript
В папке проекта создайте файл с именем tsconfig.json и скопируйте в него следующее:
compilerOptions — это набор опций, благодаря которым TypeScript понимает, как интерпретировать код и компилировать его на JavaScript. Однако, признавая TypeScript отличным языком программирования, не стоит забывать, что его необходимо компилировать на старый добрый JavaScript перед применением в производственной среде. Мы не будем подробно останавливаться на каждой опции, обратим лишь внимание на одну из них — outDir . Именно она сообщает место сохранения окончательного кода JS. В данном руководстве TS будет размещать код в директории dist , расположенной в корневом каталоге проекта.
Опция include информирует транспилятор, где искать файлы с кодом TS, а опция exclude явно указывает, какие компоненты исключить.
Исходные директории
Обратите внимание, что опция include в tsconfig.json ссылается на директорию src , которую нам еще предстоит создать в каталоге проекта. Именно здесь будет размещаться весь бэкенд-код. Также нам понадобится директория frontend :
Преобразования package.json
Нам потребуется изменить файл package.json . Для этого откройте его и замените содержимое "scripts" на следующее:
Эти скрипты определяют команды, которые мы можем выполнять в проекте. Команда transpile транспилирует код TypeScript в JavaScript.
watch осуществляет постоянный контроль кода TypeScript и в случае внесения изменений автоматически выполняет его напрямую без предварительной транспиляции в JavaScript. Во время тестирования данная процедура может оказаться очень полезной.
Команда app запускает приложение Electron для тестирования, а build компилирует его окончательную выполняемую версию для текущей платформы, сохраняя ее в директории build .
Все три команды можно выполнить в терминале в следующем формате: npm run <command> , например npm run transpile .
Наконец, изменим значение свойства "main" на "dist/main.js" , благодаря чему Electron запустит файл main.js в своем главном процессе. Это не означает, что мы будем самостоятельно писать данный файл — он будет чуть позже транспилирован из кода TypeScript.
3. Создание бэкенда
Создадим новый файл main.ts в директории src , скопировав в нее следующий код:
Давайте разберем этот код. Сначала мы импортируем необходимые модули:
- app и BrowserWindow из electron . Первый — для взаимодействия с приложением, а второй — для управления GUI.
- express и path необходимы для обслуживания фронтенда.
Далее устанавливаем переменную const PORT для настройки порта, который будет прослушиваться сервером. Это может быть любое произвольное число. Однако советую выбирать числа в диапазоне 49152–65535 во избежание конфликтов с зарезервированными или часто используемыми портами.
На этом этапе уже начинается работа с Electron. Сначала определяем переменную win , которая будет содержать объект, представляющий окно приложения. В случае отсутствия окон приложения ее значением также может быть null .
Затем определяем функцию createWindow для создания нового окна приложения и сохраняем ее в переменной win . Применяя разные опции, задаем размер и имя окна, а функция win.loadURL дает окну команду загрузить и отобразить localhost:7259 , откуда и предоставляется HTML-файл фронтенда, который мы вскоре создадим. В завершении этого этапа определяем в этой функции обратный вызов win.on , который при закрытии окна устанавливает значение объекта win обратно на null .
До настоящего момента наш код сообщал Electron, что и как нужно делать с окном приложения, но ничего не говорил про реализацию работы самого приложения. Этой цели послужат строки с 30 по 50. С помощью app.on они определяют 3 функции обратных вызовов, которые срабатывают при определенных событиях.
При начальной инициализации процесса приложения Electron запускается событие ready , вслед за чем мы создаем новое окно приложения и отображаем его, используя функцию createWindow .
Как только закрываются все ранее открытые окна, запускается событие window-all-closed . В Windows или Linux это говорит о том, что пользователь намерен окончательно выйти из приложения, поэтому мы вызываем app.quit для завершения его работы. Однако в macOS приложения могут выполняться в фоновом режиме, пока пользователь не закроет их напрямую через панель Dock, поэтому этот особый случай учитывается в конструкции if .
В завершении этапа происходит обработка события activate , которое вызывается при переходе приложения из фонового режима на передний план. Очевидно, что это характерно только для macOS, поскольку только данная платформа позволяет приложению изначально выполняться в фоновом режиме. При запуске этого события функцией createWindow еще раз создается новое окно приложения.
Поскольку вы знакомы с Node и Express, мы не будем рассматривать код после 52 строки.
Итак, у нас есть необходимый код для запуска приложения Electron и сервера Express в фоновом режиме. Но нам по-прежнему требуется фронтенд для взаимодействия с сервером.
4. Создание фронтенда
Обратите внимание, что в ранее рассмотренном коде упоминается файл index.html . Вы, конечно, можете применять любые фронтенд-технологии на свой вкус, однако для целей данного руководства достаточно одного самого простого HTML-файла.
Скопируйте следующий код в файл index.html , расположенный в корневом каталоге проекта.
5. Тестирование приложения
На этом этапе приложение готово для сборки. Приступайте к генерации исполняемого файла, только убедившись, что все работает, как нужно.
Запускаем код командой npm run watch и внимательно следим за его изменением. Затем открываем в браузере файл index.html . Несмотря на то, что приложения Electron обычно в браузере не выполняются, по своей сути, они являются веб-приложениями, поэтому в целях удобства тестирования этот вариант вполне допустим. Electron основан на движке Chromium, в связи с чем желательно использовать Chrome, Edge или другие браузеры на базе Chromium.
Протестируйте приложение и по мере необходимости вносите любые изменения. Не забывайте обновлять окно браузера после корректировки фронтенд-кода.
Технически запуск приложения в браузере ничем не отличается от аналогичного процесса в контейнере Electron, в чем вы сами можете убедиться, запустив приложение в контейнере командой в npm run app .
Убедившись, что все работает, переходите к следующему разделу.
6. Сборка приложения
Итак, все части пазла на своих местах, и осталось только скомпилировать приложение для конечных пользователей. Выполняем npm run transpile , чтобы убедиться, что последняя версия кода преобразована в JavaScript. После этого с помощью npm run build собираем окончательную выполняемую версию приложения. Обратите внимание, что таким образом вы создаете приложение для текущей версии ОС, но, изучив опции electron-packager , вы узнаете и способы компиляции для других платформ, что позволит внести соответствующие корректировки в скрипт package.json .
Скомпилированное приложение должно находиться в новой директории build .
Заключение
Надеюсь, что благодаря этому руководству вы научились разрабатывать настольные приложения в Electron.
Читайте также: