Модель процессов
Electron унаследовал свою многопроцессную архитектуру от Chromium, что делает структуру фреймворка очень похожей на современный веб-браузер. Это руководство углубится в понятия, применённые в учебнике.
Почему не один процесс?
Веб-браузеры — невероятно сложные приложения. Помимо своей основной функции отображения веб-контента, они выполняют много дополнительных задач, таких как управление несколькими окнами (или вкладками) и загрузка сторонних расширений.
В ранние дни браузеры обычно использовали один процесс для всех этих функций. Хотя эта модель означала меньшую нагрузку для каждой открытой вкладки, это также означало, что ошибка или зависание одного сайта повлияют на весь браузер.
Модель многопроцессной архитектуры
Чтобы решить эту проблему, команда Chrome решила, что каждая вкладка будет отображаться в собственном процессе, ограничивая ущерб, который могут нанести неисправленный или вредоносный код на веб-странице приложению в целом. Один процесс браузера управляет этими процессами, а также жизненным циклом приложения в целом. Данная диаграмма из комикса Chrome визуализирует эту модель:
Приложения Electron имеют очень похожую структуру. Как разработчик приложения, вы управляете двумя типами процессов: главным и рендеринговым. Они аналогичны собственным процессам браузера и рендеринга Chrome, описанным выше.
Главный процесс
Каждое приложение Electron имеет единственный главный процесс, который является точкой входа приложения. Главный процесс работает в среде Node.js, что означает возможность require модулей и использования всех API Node.js.
Управление окнами
Основная задача главного процесса — создание и управление окнами приложения с помощью модуля BrowserWindow.
Каждый экземпляр класса BrowserWindow создаёт окно приложения, которое загружает веб-страницу в отдельном рендеринговом процессе. Вы можете взаимодействовать с этим веб-контентом из главного процесса, используя объект окна webContents.
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('https://github.com')
const contents = win.webContents
console.log(contents)
Примечание: рендеринговый процесс также создаётся для встроенных веб-элементов, таких как модуль
BrowserView. ОбъектwebContentsтакже доступен для встроенного веб-контента.
Поскольку модуль BrowserWindow является EventEmitter, вы также можете добавлять обработчики для различных событий пользователя (например, сворачивания или разворачивания окна).
При уничтожении экземпляра BrowserWindow соответствующий рендеринговый процесс также завершается.
Жизненный цикл приложения
Главный процесс также управляет жизненным циклом вашего приложения через модуль Electron app. Этот модуль предоставляет большой набор событий и методов, которые вы можете использовать для добавления пользовательского поведения приложения (например, программно завершать работу приложения, изменять значок приложения в док-станции или показывать панель «О программе»).
В качестве практического примера, приложение, показанное в руководстве по быстрому началу работы, использует app API для создания более родного опыта взаимодействия с окнами приложения.
// quitting the app when no windows are open on non-macOS platforms
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
Родные API
Для расширения функций Electron за пределы обертки Chromium для веб-содержимого, главный процесс также добавляет пользовательские API для взаимодействия с операционной системой пользователя. Electron предоставляет различные модули, которые контролируют родную функциональность рабочего стола, такие как меню, диалоговые окна и значки трея.
Полный список модулей главного процесса Electron можно найти в нашей документации API.
Рендеринговый процесс
Каждое приложение Electron запускает отдельный рендеринговый процесс для каждого открытого BrowserWindow (и каждого встроенного веб-элемента). Как следует из названия, рендерер отвечает за *отображение* веб-контента. Во всех отношениях код, выполняемый в рендеринговых процессах, должен соответствовать веб-стандартам (по крайней мере, в той мере, в которой это делает Chromium).
Таким образом, все пользовательские интерфейсы и функциональность приложения в одном окне браузера должны быть написаны с использованием тех же инструментов и парадигм, что и для веб-разработки.
Хотя объяснение каждого веб-специфического стандарта выходит за рамки этого руководства, необходимо понимать следующее:
- Файл HTML является точкой входа для рендерингового процесса.
- Стиль пользовательского интерфейса добавляется через каскадные таблицы стилей (CSS).
- Выполняемый JavaScript-код можно добавить через
<script>элементы.
Кроме того, это также означает, что рендерер не имеет прямого доступа к require или другим API Node.js. Чтобы напрямую включить модули NPM в рендерер, необходимо использовать те же инструменты сборки (например, webpack или parcel), что и для веб-приложений.
Рендеринговые процессы могут быть запущены с полной средой Node.js для удобства разработки. Раньше это было значением по умолчанию, но эта функция была отключена по соображениям безопасности.
На данном этапе вы, возможно, задаетесь вопросом, как пользовательские интерфейсы вашего рендерингового процесса могут взаимодействовать с Node.js и родной функциональностью рабочего стола Electron, если эти функции доступны только из главного процесса. На самом деле, нет прямого способа импортировать скрипты содержимого Electron.
Скрипты предзагрузки
Скрипты предзагрузки содержат код, который выполняется в рендеринговом процессе до загрузки его веб-содержимого. Эти скрипты работают в контексте рендеринга, но им предоставляется больше привилегий благодаря доступу к API Node.js.
Скрипт предзагрузки можно прикрепить к главному процессу в опции webPreferences конструктора BrowserWindow.
const { BrowserWindow } = require('electron')
//...
const win = new BrowserWindow({
webPreferences: {
preload: 'path/to/preload.js',
},
})
//...
Поскольку скрипт предзагрузки разделяет глобальный интерфейс Window с рендерингом и может получить доступ к API Node.js, он служит для повышения возможностей вашего рендеринга, предоставляя произвольные API в глобальной переменной window, которые затем могут использовать ваши веб-контент.
Хотя скрипт предзагрузки разделяет глобальную переменную window с рендерингом, к которому он прикреплён, вы не можете напрямую подключить какие-либо переменные из скрипта предзагрузки к window, из-за значения по умолчанию contextIsolation.
window.myAPI = {
desktop: true,
}
console.log(window.myAPI) // => undefined
Изоляция контекста означает, что скрипты предзагрузки изолированы от основного мира рендеринга, чтобы избежать утечки любых привилегированных API в код вашего веб-содержимого.
Вместо этого используйте модуль contextBridge для безопасного выполнения этой задачи:
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true,
})
console.log(window.myAPI)
// => { desktop: true }
Эта функция невероятно полезна для двух основных целей:
- Предоставляя
ipcRendererпомощники рендерингу, вы можете использовать межпроцессное взаимодействие (IPC) для запуска задач главного процесса из рендеринга (и наоборот). - Если вы разрабатываете обёртку Electron для существующего веб-приложения, размещённого по удалённому URL, вы можете добавить пользовательские свойства в глобальную переменную рендеринга
window, которые могут использоваться для чисто настольной логики на стороне веб-клиента.
© GitHub Inc.
Licensed under the MIT license.
https://www.electronjs.org/docs/latest/tutorial/process-model