Мы будем создавать приложение ToDo с помощью библиотеки Electron. Мы затронем следующие темы: хранение данных, использование нескольких окон, взаимодействие между браузерами.
Что необходимо для этого
Я рассчитываю, что вы уже имеете представление об основных процессах и процессах браузера.
- Основы JavaScript.
- Понимание HTML/CSS.
- Установленный NodeJS.
- Базовое представление о процессах Electron.
Весь код этого проекта можно скачать на GitHub.
Настройка проекта
Чтобы не начинать с чистого листа, возьмём за основу шаблон Electron.
Примечание: рекомендую вам создать собственное, похожее приложение, после прочтения статьи. Существует много способов создать такое приложение, будет более эффективно если вы сделаете это по-своему (к тому же, трудно работать над проектом по учебнику).
- Загрузите шаблон
- Запустите
npm install
и установите все дополнительные пакеты, которые вам нужны (я установил Standard JS стиль для линтинга) - Просмотрите все файлы. Везде есть комментарии, объясняющие работу кода.
Так выглядит мой 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