Перейти к основному содержанию

Создание Вашего первого приложения

Цели обучения

В этой части руководства вы узнаете, как настроить проект Electron и написать базовое небольшое приложение. К концу этого раздела вы научитесь запускать из терминала работающее приложение Electron в режиме разработки.

Настройка проекта

Избегайте WSL

Если вы работаете на компьютере с ОС Windows, пожалуйста, не используйте Windows Subsystem for Linux (WSL) при изучении данного руководства, поскольку при попытке запуска приложения вы столкнетесь с проблемами.

Инициализация npm проекта

Для создания приложений Electron используется npm, а в качестве отправной точки используется файл package.json. Для начала создайте папку и инициализируйте в ней пакет npm с помощью npm init.

mkdir my-electron-app && cd my-electron-app
npm init

Эта команда предложит вам настроить несколько полей в файле package.json. В этом руководстве стоит придерживаться следующего:

  • точкой входа должен быть файл main.js (этот файл будет создан позже).
  • author, license, and description могут иметь любое значение, но в дальнейшем будут задействованы для упаковки.

Затем установите Electron в devDependencies своего приложения, представляющий собой список внешних зависимостей пакетов, предназначенных только для разработки и не требующихся в продакшене.

Почему Electron является зависимостью devDependency?

Это может показаться нелогичным, поскольку в продакшене используется API Electron. Однако упакованные приложения будут поставляться в комплекте с двоичным файлом Electron, что избавляет от необходимости указывать его в качестве клиентской зависимости (dependencies).

npm install electron --save-dev

После инициализации пакета и установки Electron ваш файл package.json должен выглядеть примерно так. Кроме того, теперь у вас должны появиться папка node_modules, содержащая исполняемый файл Electron, а также файл фиксации package-lock.json, в котором указаны точные версии зависимостей для установки.

package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
Дополнительные шаги по установке Electron

Если установка Electron напрямую не удается, обратитесь к документации по Расширенной установке для получения рекомендаций по зеркалам загрузки, прокси и способам устранения неполадок.

Добавление .gitignore

Файл .gitignore указывает, какие файлы и каталоги не нужно отслеживать посредством Git. Копию шаблона GitHub's Node.js gitignore следует поместить в корневую папку проекта, чтобы избежать коммитов папки node_modules.

Запуск приложения Electron

Дополнительная информация

Ознакомьтесь с документацией модели процессов Electron, чтобы лучше понять, как работают между собой множественные процессы Electron.

Скрипт main, определенный в package.json, является точкой входа в любое приложение Electron. Этот скрипт управляет основным процессом (main), который работает в среде Node.js и обеспечивает управление жизненным циклом приложения, отображением нативных интерфейсов, выполнением привилегированных операций и управлением процессами рендеринга (подробнее о них мы поговорим позже).

Перед тем как создать свое первое приложение Electron, сначала реализуем простейший сценарий, чтобы убедиться, что точка входа в основной процесс настроена правильно. Создайте в корневой папке проекта файл main.js с одной строкой кода:

main.js
console.log('Привет из Electron 👋')

Поскольку основной процесс Electron - это среда Node.js, вы можете запускать произвольный Node.js-код с помощью команды electron (можно даже использовать ее в качестве REPL). Чтобы запустить этот код, добавьте electron . к команде start в поле scripts в package.json. Эта команда укажет исполняемому модулю Electron искать основной скрипт в текущем каталоге и запускать его в режиме разработки (dev).

package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
npm run start

В терминале должно появиться сообщение Привет из Electron 👋. Поздравляем, вы выполнили первую строку кода в Electron! Далее вы научитесь создавать пользовательские интерфейсы с помощью HTML и загружать их в нативном окне ОС.

Загрузка веб-страницы внутри BrowserWindow

В Electron каждое окно выводит веб-страницу, которая может быть загружена либо из локального HTML-файла, либо с удаленного веб-адреса. В данном примере мы будем загружать локальный файл. Начните с создания базовой веб-страницы в файле index.html в корневой папке вашего проекта:

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Привет из Electron renderer!</title>
</head>
<body>
<h1>Привет из Electron renderer!</h1>
<p>👋</p>
</body>
</html>

Теперь, когда у вас есть веб-страница, вы можете загрузить ее в окно Electron BrowserWindow. Замените содержимое файла main.js следующим кодом. Каждый блок мы рассмотрим отдельно.

main.js
const { app, BrowserWindow } = require('electron')

const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})

win.loadFile('index.html')
}

app.whenReady().then(() => {
createWindow()
})

Импорт модулей

main.js (Line 1)
const { app, BrowserWindow } = require('electron')

В первой строке мы импортируем два модуля Electron с использованием стандарта CommonJS:

  • app - управляет циклом событий вашего приложения.
  • BrowserWindow - создает и управляет окнами приложения.
Module capitalization conventions

Возможно, вы заметили разницу в написании заглавных между именами модулей app и BrowserWindow. Electron следует типичным для JavaScript соглашениям, где модули в стиле именования PascalCase являются объектами-конструкторами (например: BrowserWindow, Tray, Notification), а модули camelCase - нет (например: app, ipcRenderer, webContents).

Typed import aliases

For better type checking when writing TypeScript code, you can choose to import main process modules from electron/main.

const { app, BrowserWindow } = require('electron/main')

For more information, see the Process Model docs.

ES Modules in Electron

ECMAScript modules (i.e. using import to load a module) are supported in Electron as of Electron 28. You can find more information about the state of ESM in Electron and how to use them in our app in our ESM guide.

Написание многоразовой функции для создания экземпляров окон

Функция createWindow() загружает веб-страницу в новый экземпляр BrowserWindow:

main.js (Lines 3-10)
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})

win.loadFile('index.html')
}

Вызов функции, когда приложение готово к работе

main.js (Lines 12-14)
app.whenReady().then(() => {
createWindow()
})

Многие модули ядра Electron являются генераторами событий (эмиттерами) Node.js, которые соблюдают асинхронную событийно-ориентированную архитектуру Node. Модуль app является одним из таких генераторов.

В Electron экземпляры BrowserWindows могут быть созданы только после срабатывания события ready модуля app. Дождаться этого события можно, используя API app.whenReady() и вызвав createWindow() после выполнения этого промиса.

информация

В большинстве случаев для прослушивания событий Node.js используется функция .on эмиттера.

+ app.on('ready', () => {
- app.whenReady().then(() => {
createWindow()
})

Однако Electron предоставляет app.whenReady() в качестве хелпера специально для события ready, чтобы избежать нюансов, связанных, в частности, с непосредственным прослушиванием этого события. Подробнее: electron/electron#21972.

На этом этапе команда start вашего приложения Electron должна успешно открыть окно, в котором отображается выбранная веб-страница!

Каждая веб-страница, отображаемая вашим приложением в окне, будет выполняться в отдельном процессе, называемом процессом отображения (или просто renderer). Процессы отображения имеют доступ к тем же JavaScript API и инструментарию, которые вы используете для обычной front-end разработки, например, к webpack для сборки и минификации кода или к React для создания пользовательских интерфейсов.

Управление жизненным циклом окон вашего приложения

Application windows behave differently on each operating system. Rather than enforce these conventions by default, Electron gives you the choice to implement them in your app code if you wish to follow them. You can implement basic window conventions by listening for events emitted by the app and BrowserWindow modules.

Process-specific control flow

Checking against Node's process.platform variable can help you to run code conditionally on certain platforms. Note that there are only three possible platforms that Electron can run in: win32 (Windows), linux (Linux), and darwin (macOS).

Quit the app when all windows are closed (Windows & Linux)

On Windows and Linux, closing all windows will generally quit an application entirely. To implement this pattern in your Electron app, listen for the app module's window-all-closed event, and call app.quit() to exit your app if the user is not on macOS.

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})

Open a window if none are open (macOS)

In contrast, macOS apps generally continue running even without any windows open. Activating the app when no windows are available should open a new one.

To implement this feature, listen for the app module's activate event, and call your existing createWindow() method if no BrowserWindows are open.

Because windows cannot be created before the ready event, you should only listen for activate events after your app is initialized. Do this by only listening for activate events inside your existing whenReady() callback.

app.whenReady().then(() => {
createWindow()

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

Окончательный вариант кода запуска

const { app, BrowserWindow } = require('electron/main')

const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})

win.loadFile('index.html')
}

app.whenReady().then(() => {
createWindow()

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

Опционально: Отладка из VS Code

Если вы хотите отлаживать свое приложение с помощью VS Code, вам нужно подключить VS Code как к основному процессу, так и к процессу рендеринга. Here is a sample configuration for you to run. Create a launch.json configuration in a new .vscode folder in your project:

.vscode/launch.json
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}

The "Main + renderer" option will appear when you select "Run and Debug" from the sidebar, allowing you to set breakpoints and inspect all the variables among other things in both the main and renderer processes.

launch.jsonArrayBuffer:

  • Main is used to start the main process and also expose port 9222 for remote debugging (--remote-debugging-port=9222). This is the port that we will use to attach the debugger for the Renderer. Поскольку основной процесс является процессом Node.js, тип установлен в node.
  • Renderer is used to debug the renderer process. Because the main process is the one that creates the process, we have to "attach" to it ("request": "attach") instead of creating a new one. Процесс рендерера является веб-процессом, так что отладчик, который мы должны использовать, это chrome.
  • Main + renderer is a compound task that executes the previous ones simultaneously.
Предупреждение

Because we are attaching to a process in Renderer, it is possible that the first lines of your code will be skipped as the debugger will not have had enough time to connect before they are being executed. You can work around this by refreshing the page or setting a timeout before executing the code in development mode.

Дальнейшее изучение

If you want to dig deeper in the debugging area, the following guides provide more information:

Подводя итоги

Electron applications are set up using npm packages. The Electron executable should be installed in your project's devDependencies and can be run in development mode using a script in your package.json file.

The executable runs the JavaScript entry point found in the main property of your package.json. This file controls Electron's main process, which runs an instance of Node.js and is responsible for your app's lifecycle, displaying native interfaces, performing privileged operations, and managing renderer processes.

Renderer processes (or renderers for short) are responsible for displaying graphical content. You can load a web page into a renderer by pointing it to either a web address or a local HTML file. Renderers behave very similarly to regular web pages and have access to the same web APIs.

In the next section of the tutorial, we will be learning how to augment the renderer process with privileged APIs and how to communicate between processes.