Electron

Мы будем создавать приложение ToDo с помощью библиотеки Electron. Мы затронем следующие темы: хранение данных, использование нескольких окон, взаимодействие между браузерами.

Что необходимо для этого

Я рассчитываю, что вы уже имеете представление об основных процессах и процессах браузера.

Весь код этого проекта можно скачать на GitHub.

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

Чтобы не начинать с чистого листа, возьмём за основу шаблон Electron.

Примечание: рекомендую вам создать собственное, похожее приложение, после прочтения статьи. Существует много способов создать такое приложение, будет более эффективно если вы сделаете это по-своему (к тому же, трудно работать над проектом по учебнику).

  1. Загрузите шаблон
  2. Запустите npm installи установите все дополнительные пакеты, которые вам нужны (я установил Standard JS стиль для линтинга)
  3. Просмотрите все файлы. Везде есть комментарии, объясняющие работу кода.

Так выглядит мой package.json файл. Мы разберём остальные файлы, когда начнём добавлять в них код.

 

И наконец, запустите npm start, чтобы убедиться что всё работает (я внёс изменения в HTML, чтобы отобразить текст).

 

Настройка

Начнём настраивать шаблон (весь код есть на GitHub).

Use Strict

Я добавил “use strict” в начало каждого JS файла, чтобы использовать строгий JavaScript. С правилами строгого режима можно ознакомиться здесь.

Объектно-Ориентированный код

Мы будем применять ООП, используя классы, например класс Window для создания окон браузера (не путайте с глобальным объектом window). Вы можете добавлять дополнительные классы для других окон мы же сделаем два окна.

 

Этот класс позволяет создавать окна с конфигурацией по умолчанию, загружать HTML-файл, открывать devtools в новом окне и корректно отображать окно, когда оно готово к показу. В нём также есть все методы BrowserWindow и всё, что мы добавим сверху.

После завершения рендеринга страницы, срабатывает событие ready-to-show. Это предотвращает мерцание на странице, когда подгружается много контента. Подробнее об этом можно прочитать здесь.

Если вы незнакомы с объектами JavaScript, рекомендую этот краткий обзор.

Примечание: вам решать, как проектировать своё приложение. Вам не обязательно использовать классы. Старайтесь писать «чистый» код и избегайте утечек памяти.

Подчищаем Main.js

Я удалил большую часть кода из шаблона, чтобы было наглядней. Кроме того, я добавил функцию main, которая на данный момент служит только для создания нового окна.

 

Системный шрифт в CSS

Подключить системный шрифт довольно просто, используйте font: caption в CSS (я добавил тег прямо в HTML).

Окончательная структура файлов

Структура файлов будет выглядеть так:

 

  • index.html — HTML код Todo List Window
  • index.js — JS рендер для Todo List Window
  • add.html — HTML код Add Todo Window
  • add.js — JS рендер для Add Todo Window
  • style.css — все CSS стили
  • DataStore.js — обрабатывает данные JSON
  • main.js — точка входа основного процесса
  • Window.js — класс для создания окон

Что делает это приложение

У нас есть базовый шаблон, теперь давайте разберёмся, как будет выглядеть приложение, и как работают его компоненты.

Todo List Window

  • Отображает Задачи.
  • Отправляет данные о событиях в основной процесс, например delete todo.
  • Отправляет запрос на создание окна «Add Todos» в main process при создании новой Задачи.

Add Todos Window

  • Input для добавления Задачи.
  • Отправляет данные о новой Задаче в main process.

Main process (основной процесс)

  • Вносит и удаляет Задачи.
  • Считывает Задачи.
  • Отправляет Задачи в окно Todo List при загрузки приложения и обновлении.
  • Принимает данные из обоих окон. Управляет обменом данными между окнами.
  • Создаёт окна Todo List и Add Todo, когда поступает запрос из главного окна.

Хранение данных

У нас есть несколько вариантов хранения данных.

  • Local Storage API — хранилище браузера.
  • Disk Storage — хранение на диске пользователя в любом формате, например JSON, CSV и т.д.
  • Database — хранение в базе данных, локально или на сервере.

Каждый вариант имеет свои плюсы и минусы. Мы рассмотрим их все.

Поток данных

В целом поток данных/событий выглядит примерно так:

 

Эта схема выглядит как бомба с кучей проводов, которые нужно перерезать … постарайся не пугаться. Есть и другие способы доступа к main process, чтобы непосредственно добавлять/модифицировать Задачи, например можно использовать простую модель или electron.remote.

Предварительный просмотр

На данном этапе у приложения минимум стилизации, сейчас нас интересует поток данных. После закрытия приложения, Задачи сохраняются.

 

Пишем менеджер данных

Займёмся данными. Я уже упоминал, что есть три способа хранить данные: local storage API , на диске или в базе данных.

Локальное хранилище и базы данных

Их можно легко переносить на веб-сайт и обратно. В этом приложении вы будете обрабатывать данные с помощью JS рендера, вот так:

 

В случае с базой данных, код будет выглядеть похожим образом, используйте вызов API либо на рендер, либо на main process. Мы сосредоточимся на хранении файлов.

Хранение данных в файловой системе

Где мы будем хранить наши данные? Чаще всего они хранятся в папке «AppData», её расположение отличается в каждой операционной системе. Мы будем хранить данные здесь:

Linux: ~/.config/<App Name>
Mac OS: ~/Library/Application Support/<App Name>
Windows: C:\Users\<user>\AppData\Local\<App Name>

Чтобы вернуть корректный адрес, в Electron можно использовать метод app.getPath('userData'). Чтобы сохранять данные на диск, можно написать функцию или воспользоваться библиотекой.

Используем библиотеку для хранение данных

Сохранять данные в Node довольно просто — нужно конвертировать данные в строку и использовать fs.writeFile. Так как мы используем Electron, то будем использовать библиотеку, созданную специально для него.

Эта библиотека отвечает за создание файла JSON, а также за чтение и запись в него. Например:

 

DataStore.js

Обратите внимание, что electron-store использует конструктор объекта для Store . Давайте расширим этот объект ( так же, как мы сделали с BrowserWindow ), чтобы мы могли хранить несколько списков Задач, если захотим.

Класс DataStore будет выглядеть так:

 

Теперь все Задачи хранятся как массив в объекте, а также мы имеем методы для взаимодействия с ними. Хранение данных в объекте предотвращает выполнение затратных операций с файлами, каждый раз когда мы хотим получить доступ к Задачам. Есть плюсы и минусы такого подхода, но это выходит за рамки статьи.

Методы get и set относятся к модулю electron-store, они обрабатывают файл JSON.

Возвращать this не обязательно, но это хороший приём, который позволяет создать цепочку вызовов. Вот так, DataStore выглядит на практике:

 

Вот что происходит в папке приложения (это Linux):

 

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

Посмотрим на новую схему

Давайте наконец соединим все кусочки. Помните эту схему?

 

На данный момент мы уже создали Data Manager ( DataStore.js ) и можем создавать окна с помощью класса Window. Остались только обработчики событий (линии на схеме).

Примечание:

Я убрал «Complete to do», чтобы было проще.

Структура файлов

Хочу напомнить, как выглядит структура файлов на данный момент:

 

Прослушиватели событий в Main Process

Используем ipcMain.on() для прослушивания и myWindow.webContents.send() для отправки событий из основного процесса.

Согласно нашей схеме, нам нужно прослушивать:

  • Create Todo
  • Delete Todo
  • Add Todo
  • Create Todo Window

Так выглядит окончательная версия main.js, в который я добавил необходимые прослушиватели:

 

Здесь всё предельно просто, разве что, можно немного подчистить. Мы прослушиваем событие, после чего используем экземпляр todosData из DataStore, для обработки данных.

Обработчики событий для Todo List Window

Вот куда мы будем отправлять все события, которые мы слушаем в main.js. Здесь будет задействован выбор элементов DOM, поэтому в первую очередь, давайте посмотрим на HTML.

 

Для стилизации, я использую Spectre.css. Здесь нужно обратить внимание на button id и ul id.

JS файл для окна Todo List:

 

После нажатия на кнопку мы отправляем событие ‘add-todo-window’ в main process, который в свою очередь открывает Add Todo Window.

Далее, мы прослушиваем событие ‘todos’, которое передаётся из main process при первой загрузки окна, и когда в Задачу вносятся изменения.

После этого мы генерируем HTML для этих Задач и добавляем прослушиватели событий, которые обрабатывают клик по элементу, отправляя событие ‘delete-todo’ в main process.

Обработчики событий для Add Todo Window

Здесь всё очень просто.

Основная часть HTML — это форма:

 

А это, JS:

 

Как только форма отправлена, мы передаём введённый текст. После этого очищаем поле input, чтобы можно было ввести другие значений.

 

Вот и всё!

Резюме

Мы рассмотрели следующие темы:

  • Хранение файлов.
  • Local Storage API и База данных (кратко).
  • Где хранить данные.
  • Несколько окон.
  • Коммуникация между окнами (add todo window → main process → todo list window).
  • Поток данных в приложении, созданном на electron.
  • ООП для расширения объектов.

Как можно улучшить приложение

  • Удалить стандартного меню и создать собственное.
  • Добавить CSS переходы.
  • Использовать «скрытый браузер» для создания нового процесса, чтобы сохранять Задачи.

 

Перевод статьи CodeDraken: Build a Todo App with Electron