Как стать автором
Обновить

Разработка простого приложения непростым способом

Время на прочтение27 мин
Количество просмотров6.5K

Всем привет!


Относительно давно мне прилетела задача по учебе написание курсовой, и я её наконец-то написал. Чтобы добро не пропадало, я решил оформить её (курсовую) в виде статьи. Надеюсь, статья будет полезна не только для тех, кто хочет погрузиться в мир Web разработки, но и так же для тех, кто считает, что современный веб не так уж и сложен, чтобы платить высокую ЗП.


Итак, тема курсовой:


Разработать программу «Поиск». Программа должна осуществлять поиск заданных слов в текстовом файле. Слова последовательно вводятся с клавиатуры. Для каждого слова должно определяться количество вхождений и номера строк текста. Если указанное слово в файле отсутствует, то программа должна выводить соответствующее сообщение.

Разработкой всяких SPA и PWA я занимаюсь очень давно, но вот как-то не было случая пощупать Electron. Не спеша закрывая MS Visual Studio, подумал, почему бы нет...


И, пожалуй, начнём с инструментов разработчика.




Современное программное обеспечение разрабатывается с использованием ИСР (IDE) — Интегрированной среды разработки. Такие среды разработки позволяют программисту разрабатывать качественное программное обеспечение (ПО), проходя этапы реализации разработки, начиная от интерактивного написания программного кода, компиляцией, сборки и отладки, автоматическим запуском тестов, заканчивая удобными и всесторонне настраиваемыми другими инструментами разработчика. До появления ИСР разработка отнимала много времени даже самого простейшего программного продукта. При этом так же страдало качество разработки. ИСР в первую очередь предназначены автоматизировать процесс разработки. Чем сложнее технология и окружение, тем гибче и сложнее будет ИСР и инструменты которая она в себя может внедрить.


Сейчас на рынке существует достаточно много ИСР. Есть проприетарные решения и есть бесплатные основанные на открытом исходном коде. На момент написания данной работы на мой взгляд первое место занимает ИСР — Visual Studio Code, разработанное Microsoft для Windows, Linux и macOS. Позиционируется как «лёгкий» редактор кода для кроссплатформенной разработки веб- и облачных приложений. Включает в себя отладчик, инструменты для работы с Git, подсветку синтаксиса, IntelliSense и средства для рефакторинга. Имеет широкие возможности для кастомизации: пользовательские темы, сочетания клавиш и файлы конфигурации. Распространяется бесплатно, разрабатывается как программное обеспечение с открытым исходным кодом, но готовые сборки распространяются под проприетарной лицензией. ИСР Visual Studio Code была разработана используя ту технологию, которая применена для написания этого проекта…



ИСР - Visual Studio Code


На втором месте в моём рейтинге ИСР – это PhpStorm. Это коммерческая кросс-платформенная интегрированная среда разработки для Web разработчиков. Разрабатывается компанией JetBrains на основе платформы IntelliJ IDEA. PhpStorm представляет собой интеллектуальный редактор для PHP, HTML и JavaScript с возможностями анализа кода на лету, предотвращения ошибок в коде и автоматизированными средствами рефакторинга для PHP и JavaScript. Автодополнение кода в PhpStorm поддерживает спецификацию PHP 5.3, 5.4, 5.5, 5.6, 7.0, 7.1, 7.2 и 7.4 (современные и традиционные проекты), включая генераторы, сопрограммы, пространства имен, замыкания, типажи и синтаксис коротких массивов. Имеется полноценный SQL-редактор с возможностью редактирования полученных результатов запросов.


Пользователи могут расширить функциональность среды разработки за счет установки плагинов, разработанных для платформы IntelliJ, или написав собственные плагины.


Для разработки приложения "Поиск" я использовал PhpStorm с его экосистемой разработки, поскольку я с этой средой уже 7 лет.



ИСР – PhpStorm


Основная часть


1. Технологический стек разработки


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


Одно из основного технологического стека разработки является Electron — библиотека с открытым исходным кодом, разработанная командой, создавшей GitHub, для создания кроссплатформенных приложений с помощью HTML, CSS и JavaScript. Electron достигает этого путем объединения Chromium и Node.js в единую среду выполнения, а приложения могут быть собраны для выполнения под Mac, Windows и Linux.


Electron был написан в 2013 году как фреймворк для создания текстового редактора Atom. Оба приложения были выпущены весной 2014 года. С тех пор Electron стал популярным инструментом, используемым разработчиками приложений с открытым исходным кодом стартапами и большими компаниями.


Chromium — это проект браузера с открытым исходным кодом, целью которого является создание более безопасного, быстрого и стабильного способа для всех пользователей Интернета работать в Интернете. Chromium является основой браузера Google Chrome. Electron использует только библиотеку рендеринга от Chromium для поддержки окон.


Node.js — программная платформа, основанная на движке V8 (транслирующем JavaScript в машинный код), превращающая JavaScript из узкоспециализированного языка в язык общего назначения. Node.js добавляет возможность JavaScript взаимодействовать с устройствами ввода-вывода через свой API (написанный на C++), подключать другие внешние библиотеки, написанные на разных языках, обеспечивая вызовы к ним из JavaScript-кода. Node.js применяется преимущественно на сервере, выполняя роль веб-сервера, но есть возможность разрабатывать на Node.js и десктопные оконные приложения (при помощи NW.js, AppJS или Electron для Linux, Windows и macOS) и даже программировать микроконтроллеры (например, tessel и espruino). В основе Node.js лежит событийно-ориентированное и асинхронное (или реактивное) программирование с неблокирующим вводом/выводом.


Electron работает по принципу работы браузера Google Chrome – имеется один основной процесс и n-ное количество процессов рендеринга. Каждый процесс рендеринга имеет доступ к основному процессу.



Примитивная схема работы Electron


Для общения между процессами в Electron используется механизм IPC.


IPC ( inter-process communication) — обмен данными между потоками одного или разных процессов. Реализуется посредством механизмов, предоставляемых ядром ОС или процессом, использующим механизмы ОС и реализующим новые возможности IPC. Может осуществляться как на одном компьютере, так и между несколькими компьютерами сети.


Из механизмов, предоставляемых ОС и используемых для IPC, можно выделить:


  • механизмы обмена сообщениями;
  • механизмы синхронизации;
  • механизмы разделения памяти;
  • механизмы удалённых вызовов (RPC).

В нормальных браузерах, веб-страницы обычно выполняются в изолированной среде, и им не разрешается доступ к нативным ресурсам ОС. Пользователи Electron'а, однако, имеют право использовать API Node.js на веб-страницах, позволяя взаимодействовать на низком уровне операционной системы.


Современная разработка того или иного приложения не обходится без сторонних модулей. Как правило, в сторонних модулях всегда можно найти уже реализованный тот или иной функционал и нет смысла заниматься «велосипедостроением». Для реализации поставленной задачи я воспользуюсь несколькими сторонними решениями. Часть из этих решений будет необходимо в качестве инструментария для разработки.


В "нашем" мире есть специальные реестры для хранения отдельных решений под разные задачи эти решения именуются пакетами. Для загрузки этих пакетов используется, как правило, кроссплатформенное приложение специальным образом разработано для конкретного реестра. Язык модуля и сами модули, входящие в состав пакета, может быть разным. Рассмотрим, на мой взгляд, один из самого популярного реестра ПО (программного обеспечения) – npm (Node Package Manager), который недавно купил GitHub (с 2018 года принадлежит Microsoft).


Npm состоит из трех отдельных компонентов:


  • веб-сайт;
  • интерфейс командной строки (CLI);
  • реестр.

Используя интерфейс командной строки (CLI), можно загружать пакеты к себе в папку из реестра, а также желающие могут поделиться своими разработками загрузив в реестр собственное решение.


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


1.2 Модули / пакеты для разработки


Пакеты для разработки можно разделить на две категории:


  1. Пакеты необходимые для создания web приложения Electron – инструментальные пакеты;
  2. Пакеты, которые входят в состав разработанного приложения Electron.

Первый тип пакетов необходим исключительно для сборки (создания) web приложения и не входит в состав самого приложения. Второй тип наоборот может входить частично или полностью в готовое web приложение.


Пакеты первой категории, применённые для разработки приложения «Поиск»:


  • Webpack, webpack-cli, webpack-merge. Webpack – это система сборки проекта, которая предоставляет не только бандлинг (компоновку) модулей, но и может выполнять задачи, которые требуются разработчику для работы своего проекта. К тому же, Webpack не ограничивается JavsScript-файлами, он может работать с другой статикой вроде CSS, картинок, html-компонентов и др.
    Webpack также поддерживает очень полезную функцию — code splitting (разбиение кода). Большое приложение можно разбить на куски, которые загружаются по мере необходимости.
  • @ babel/coreBabel.JS это транспайлер, переписывающий код javascript стандарта ES5 в код на стандарт ES-2015+. babel/core — ядро, которое непосредственно занимается транспиляцией.
  • @ babel/preset-env – надстройка для @babel/core, позволяющая управлять параметрами транспиляции, указав целевые среды, для которых требуется работоспособность вашего кода. Настройки для «babel/preset-env» в этом проекте находятся в файле .browserslistrc, находящийся в корне. Более подробно ознакомиться с форматом задания целевых сред можно тут.
  • babel-plugin-prismjs – плагин для babel. Этот плагин позволяет рассматривать PrismJS как стандартный модуль и настраивать языки, плагины и темы, которые необходимо использовать с Prism.
  • babel-loader – загрузчик для Webpack. Использует babel/core для транспиляции на этапе сборки проекта.
  • copy-webpack-plugin – Плагин для Webpack. Копирует отдельные файлы или целые каталоги в папку сборки.
  • css-loader – загрузчик для Webpack. Интерпретирует import и url() как import/require() и разрешает (resolve) пути к контенту.
  • html-webpack-plugin – Плагин для Webpack. упрощает создание html index файла в процессе сборки Webpack’ом. Упрощение может заключаться, например, в обновлении ссылок на ресурсы проекта, которые могут включать в своем названии текущий хэш сборки.
  • mini-css-extract-plugin – Плагин/загрузчик для Webpack. Для некоторых модулей и фреймворков выносит блоки стилевой разметки из этих модулей в отдельный .css файл, который непосредственно подключается к проекту.
  • null-loader – Загрузчик для Webpack. С помощью этого загрузчика можно "обнулить" некоторые ресурсные модули, и не позволить включать их в основную сборку проекта.
  • Pug, pug-loader, pug-plain-loader – Pug-это высокопроизводительный шаблонизатор, навеянный языком разметки Haml и реализованный с помощью JavaScript для Node.js и браузеров. pug-loader, pug-plain-loader – загрузчик для Webpack, позволяющий выполнять препроцессинг шаблона на этапе сборки, а не на этапе использования.
  • sass-loader – Загрузчик для Webpack. sass (Syntactically Awesome Stylesheets) – это метаязык на основе CSS, предназначенный для увеличения уровня абстракции CSS кода и упрощения файлов каскадных таблиц стилей. sass-loader запускает интерпретацию данного метаязыка на этапе сборки проекта в классический CSS по аналогии с pug.
  • style-loader – позволяет включать css стили в бандл сборки и погружать css в тэг <style> в процессе работы Web приложения.
  • vue-loader, vue-template-compiler – необходимы для сборки файлов .vue, которые имеют определённую структуру. vue-template-compiler используется для предварительной компиляции шаблонов Vue (секция template) в функции рендеринга, чтобы избежать накладных расходов на компиляцию во время выполнения.

Пакеты второй категории, применённые для написания приложения «Поиск»:


  • prismjs – Prism, это легкий, расширяемый синтаксический инструмент для подсветки синтаксиса, созданный с учетом современных веб-стандартов. Он используется на тысячах веб-сайтов, включая некоторые из тех, которые вы посещаете ежедневно.
  • Vue – Прогрессивный JavaScript Framework. Данный Framework является основой для приложения «Поиск». Этот Framework был написан одним из бывших разработчиков Google — Эваном Ю.
  • Vuex – это контейнер, в котором хранится состояние приложения. Хранилище Vuex реактивно. Когда компоненты Vue полагаются на его состояние, то они будут реактивно и эффективно обновляться, если состояние хранилища изменяется. Нельзя напрямую изменять состояние хранилища. Единственный способ внести изменения — явно вызвать мутацию. Это гарантирует, что любое изменение состояния оставляет след и позволяет использовать инструментарий, чтобы лучше понимать ход работы приложения.
  • vue-prism-editorкомпонент vue основанный на prismjs. Данный компонент предоставляет обёртку prismjs, выполненную в парадигме разработки однофайловых компонентов vue и предоставляющий доступ к основным настройкам данного редактора.
  • electron-find – Представляет из себя модуль для node.js в котором реализованы методы взаимодействия с electron, реализующие поиск по открытой странице, а также минималистический интерфейс поиска.

2. Разработка приложения «Поиск»


2.1 Подготовка разработки


Разработка приложения «Поиск» будет осуществляться под операционной системой Windows. Для разработки под другими операционными системами будет меняться только использование классических стандартных базовых утилит запуска приложений. Компиляция кроссплатформенных приложений из-под любой OC (операционной системы) так же присутствует.


Для начала необходимо установить базовое программное обеспечение для текущей платформы. Установим Node.JS. Перейдя на страницу https://nodejs.org/ru/ загрузим установочный файл рекомендованный для большинства пользователей и выполним установку. В комплекте с Node.JS будет так же установлен npm (Node Package Manager) в виде интерфейса командной строки (CLI).


После установки Node.JS необходимо создать папку под будущий проект, вызвать интерфейс командной строки, перейти вновь созданную папку и выполнить:


npm init

Далее мастер создания нового проекта предложит ввести:


  1. Имя пакета;
  2. Версию проекта;
  3. Описание проекта;
  4. Файл JavaScript точки входа;
  5. Команду для тестирования проекта;
  6. Git репозиторий;
  7. Ключевые слова, по которым можно будет найти данный проект, если последний будет опубликован в реестре npm;
  8. Имя автора;
  9. Тип лицензирования, по которому будет распространяться данный проект, если последний будет опубликован в реестре npm;

В завершении мастера будет выведена часть структуры описания проекта в формате JSON.



Процесс создания нового проекта используя npm мастер.


После показа структуры, необходимо нажать Enter. В результате в директории проекта появится файл: package.json, в котором будут отражены выше введённые нами данные.


Далее, необходимо открыть данный файл в ИСР (в моём случае PhpStorm) и продолжить редактировать, внеся изменения вручную сохраняя синтаксис JSON структуры.


package.json
{
  "name": "stext",
  "version": "1.0.0",
  "description": "Курсовая работа: Тема: Разработать программу «Поиск». Программа должна осуществлять поиск заданных слов в текстовом файле. Слова последовательно вводятся с клавиатуры. Для каждого слова должно определяться количество вхождений и номера строк текста. Если указанное слово в файле отсутствует, то программа должна выводить соответствующее сообщение",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "electron .",
    "dev": "webpack --mode=development --config webpack.dev.js --progress",
    "build": "webpack --config webpack.prod.js --env.F --mode=production --progress --hide-modules",
    "pack": "electron-builder --dir",
    "dist": "electron-builder"
  },
  "build": {
    "appId": "roman.gavrilow.ru.stext",
    "icon": "app/mainicon.png",
    "win": {
      "target": [
        {
          "target": "nsis",
          "arch": [
            "x64"
          ]
        }
      ]
    }
  },
  "author": "roman@gavrilow.ru",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.9.0",
    "@babel/preset-env": "^7.9.5",
    "babel-loader": "^8.1.0",
    "babel-plugin-prismjs": "^2.0.1",
    "copy-webpack-plugin": "^5.1.1",
    "css-loader": "^3.5.1",
    "electron": "^8.2.1",
    "electron-builder": "^22.4.1",
    "html-webpack-plugin": "^4.0.4",
    "mini-css-extract-plugin": "^0.9.0",
    "null-loader": "^3.0.0",
    "prismjs": "^1.20.0",
    "pug": "^2.0.4",
    "pug-loader": "^2.4.0",
    "pug-plain-loader": "^1.0.0",
    "sass-loader": "^8.0.2",
    "style-loader": "^1.1.3",
    "vue": "^2.6.11",
    "vue-loader": "^15.9.1",
    "vue-template-compiler": "^2.6.11",
    "vuex": "^3.1.3",
    "webpack": "^4.42.1",
    "webpack-cli": "^3.3.11",
    "webpack-merge": "^4.2.2"
  },
  "dependencies": {
    "electron-find": "^1.0.6",
    "vue-prism-editor": "^0.5.1"
  }
}

Выше под спойлер спрятан окончательный текст фала package.json. Для разработки программы поиск были внесены следующие изменение в этот файл:


Секция "scripts"


  • "start": "electron .", команда запускает Electron приложение. Точка в конце означает, что будет запущен основной процесс, в котором будет выполнятся скрипт, указанный в секции "main".
  • "dev": "webpack --mode=development --config webpack.dev.js --progress", команда запускает сборку проекта в режиме разработки. Этот режим не предусматривает, минификацию и обфускацию модулей и предназначен исключительно для тестирования проекта в процессе разработки.
  • "build": "webpack --config webpack.prod.js --env.F --mode=production --progress --hide-modules", команда запускает сборку проекта с всевозможными оптимизациями, которые позволяют сократить размер модулей.
  • "pack": "electron-builder --dir", команда собирает Electron приложение в папку «dist\» относительно корня проекта.
  • "dist": "electron-builder" — команда выполняет сборку Electron приложения, а также подготавливает дистрибутив для распространения данного программного продукта в виде установочного файла.

Далее в секции devDependencies и dependencies вручную указываются зависимые пакеты и их версии, которые будут применены в данном проекте. Эти пакеты были рассмотрены выше в разделе 1.2


После наполнения package.json всеми необходимыми данными, следует запустить npm с параметром install для загрузки всех необходимых зависимостей из реестра npm. По окончанию загрузки в корне проекта появится каталог node_modules с нужными пакетами и зависимостями от которых они сами зависят, ведь сами пакеты так же могут быть созданы с другими зависимостями, а те, в свою очередь, с другими…


2.2 Разработка


     2.2.1 Интерфейс окна приложения.


Интерфейс приложения Electron описывается в файле который имеет название указанный в секции main конфигурационного файла package.json. В моём случае там указан файл "main.js".


Импортируем необходимые модули:


const { app, BrowserWindow, globalShortcut, Menu, dialog } = require('electron');

  • app — имплементирует в себе функции для работы с главным процессом Electron приложения.
  • BrowserWindow – класс для создания render процессов.
  • globalShortcut – интерфейс для установки и прослушивания глобальных сочетаний клавиш в операционной системе.
  • Menu – класс для работы с системным меню приложения.
  • Dialog – интерфейс для вызова и настройки системного диалога.

Напишем функцию создания окна рендеринг процесса. Чтобы уместится в размеры курсовой, придется опустить подробности создания окна. Более подробнее можно будет найти в документации проекта Electron. Приведу только листинг функции создания окна с комментариями:


main.js
const { app, BrowserWindow, globalShortcut, Menu, dialog } = require('electron');

let win;

const isMac = process.platform === 'darwin';

function createWindow () {
    // Создаем окно браузера.
    win = new BrowserWindow({
        width: 800,
        height: 600,
        center: true,
        title: 'Поиск текста в файле. Курсовая Гаврилов Р.С.',
        icon: 'app/mainicon.png',
        webPreferences: {
            nodeIntegration: true
        }
    });

    // и загрузить index.html приложения.
    win.loadFile('app/index.html');

    // Раскомментировать, если хотим открыть окно инструментов разработчика.
    //win.webContents.openDevTools();

    // Подписываемся на событие "focus", которое срабатывает при фокусировки окна рендеринг процесса
    // и регистрируем глобальное сочетание клавиш Ctrl + F
    win.on('focus', () => {
        globalShortcut.register('CommandOrControl+F', function () {
            if (win && win.webContents) {
                // межпроцессная отправка сообщения "on-find" в ренеринг процесс.
                win.webContents.send('on-find')
            }
        })
    });

    // Подписываемся на событие "blur", которое срабатывает при потере фокуса окна рендеринг процесса
    // и удаляем глобальную регистрацию сочетания клавиш Ctrl + F
    win.on('blur', () => {
        globalShortcut.unregister('CommandOrControl+F')
    });

}

const template = [
    {
        label: 'Файл',
        submenu: [
            {
                label: 'Открыть',
                click: async () => { // асинхронная функция которая будет вызвана при клике на меню "Открыть"
                    // вызов системного диалогового окна открытия файла
                    let files = await dialog.showOpenDialog(win,{ properties: ['openFile'] });

                    if (win && win.webContents) {
                        // межпроцессная отправка сообщения "on-files-select" массивом выбранных файлов в ренеринг процесс.
                        await win.webContents.send('on-files-select', files)
                    }
                }
            },

            { type: 'separator' }, // разделитель меню.
            isMac ? { role: 'close' } : { role: 'quit' } // закрытие приложения используя внутренние механизмы Electron
        ]
    },
    {
        label: 'Поиск',
        submenu: [
            {
                label: 'Найти',
                click: async () => { // функция которая будет вызвана при клике на меню "Найти"
                    if (win && win.webContents) {
                        // межпроцессная отправка сообщения "on-find" в ренеринг процесс.
                        win.webContents.send('on-find')
                    }
                }
            }
        ]
    }
];

app.whenReady().then(function(){
    createWindow();
});

app.on('will-quit', () => {
    // Отменяем регистрацию всех сочетаний.
    globalShortcut.unregisterAll()
});

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);

Для создания меню приложения необходимо вызвать метод класса Menu Menu.buildFromTemplate(template), где template представляет из себя структуру в формате JSON или JavaScript Object. Данную структуру с некоторыми комментариями можно найти в том же файле "main.js". Полный листинг регистрации меню выглядит так:


const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);


Интерфейс приложения «Поиск»


     2.2.2 Отправка сообщений используя IPC.


События, которые происходят при нажатии меню или детектирования срабатывания зарегистрированных горячих клавиш, реализуются в главном процессе Electron. Для того, чтобы передать какую-либо информацию render процессам, необходимо отправить IPC сообщение. В Electron это можно сделать несколькими способами, я использовал способ, который реализуется через метод класса BrowserWindow:


win.webContents.send('on-find')
await win.webContents.send('on-files-select', files)

Соответственно, приём этих сообщений можно найти в файле «src/electron.js»


ipcRenderer.on('on-find', (e, args) => {

});

ipcRenderer.on('on-files-select', (e, args) => {

});

'on-find' – сообщение показа окна поиска текста.
'on-files-select' – сообщение, присылаемое на реакцию выбора файла, который необходимо открыть в редакторе приложения «Поиск». Вместе с сообщением присылаются полезные данные в виде массива полных путей к выбранным файлам. Поскольку в настройках диалогового окна выбора файлов указан выбор только одного файла, то массив приходящий вместе с сообщением содержит в себе только один элемент.


     2.2.3 Редактор текстового файла


Ядро функционала приложения «Поиск» основано на прогрессивном фреймворке Vue. В отличие от фреймворков-монолитов, Vue создан пригодным для постепенного внедрения. Его ядро в первую очередь решает задачи уровня представления (view), что упрощает интеграцию с другими библиотеками и существующими проектами. С другой стороны, Vue полностью подходит и для создания сложных одностраничных приложений (SPA, Single-Page Applications), если использовать его совместно с современными инструментами и дополнительными библиотеками.


Vue частично реализует шаблон Model-View-ViewModel (MVVM) проектирования архитектуры приложения. Представлен в 2005 году Джоном Госсманом (John Gossman), как модификация шаблона Presentation Model. Ориентирован на современные платформы разработки, такие как Windows Presentation Foundation, Silverlight от компании Microsoft.


MVVM удобно использовать вместо классического MVC и ему подобных в тех случаях, когда в платформе, на которой ведётся разработка, есть «связывание данных». В шаблонах проектирования MVC/MVP изменения в пользовательском интерфейсе не влияют непосредственно на модель, а предварительно идут через Контроллер (англ. Controller) или Presenter. В таких технологиях как WPF и Silverlight есть концепция «связывания данных», позволяющая связывать данные с визуальными элементами в обе стороны. Следовательно, при использовании этого приёма применение модели MVC, становится крайне неудобным из-за того, что привязка данных к представлению напрямую не укладывается в концепцию MVC/MVP.


Важной концепцией Vue являются компоненты. Эта абстракция позволяет собирать большие приложения из маленьких «кусочков». Они представляют собой пригодные к повторному использованию объекты. Если подумать, почти любой интерфейс можно представить, как дерево компонентов:



Во Vue компонент — это, по сути, экземпляр Vue с предустановленными опциями.


Для создания Vue приложения, используя инструмент разработки Webpack, необходимо создать так называемый файл вхождения (entry). Этот файл представляет из себя обычный JavaScript с расширением «.js». В моём проекте этот файл находится по пути «src/main.js». Данный файл является отправной точкой для формирования Web приложения, рекурсивно переходя по импортируемым модулям, и встраивая их в общий бандл (bundle).


В свою очередь, основное конфигурирование сборщика Webpack реализовано в файле webpack.common.js, где указывается в том числе скрипт точки входа. В этом проекте конфигурация Webpack разбита на три логические части:


  • webpack.common.js
  • webpack.dev.js
  • webpack.prod.js

Тема конфигурирования Webpack может занимать ещё как минимум две такие же статьи, поэтому на этом поставим точку.


Создадим однофайловый компонент Vue, в котором будет размещён компонент текстового редактора vue-prism-editor, описанный в разделе 1.2 подключаемых сторонних модулей. Данный компонент и будет основной страницей (поскольку она одна) для приложения «Поиск».


Однофайловый компонент Vue логически разделён на 3 составные части: шаблон, логика и стили. Это всё неразрывно связаны между собой. См. файл “src/app.vue”. В секции template можно увидеть использование директивы lang="pug", что даёт указание vue-loader пропустить содержимое этой секции через pug шаблонизатор, который преобразует pug стиль вёрстки в html синтаксис. В стандартном виде в этой секции, вёрстка макета страницы происходит в формате html.


В секции <script> разрабатывается логика компонента. Так как разработчиками Vue был заложен функционал жизненного цикла компонента, то компонент может реализовать и обработать в себе хуки (hooks) необходимые разработчику для более глубокой интеграции в событийную модель фреймворка. На необходимом определённом этапе событийной модели, разработчик может реализовать тот или иной функционал компонента, который заложен в логику работы как самого компонента, так и используемых подкомпонентов или других фреймворков. В приложении «Поиск» компонент реализует хук created(), который вызывается в процессе инициализации компонента. В этом хуке происходит подписка на глобальную событийную шину, которая была инициализирована в файле-точке входа “src/main.js”. В проекте используется только одно глобальное событие (ON_SELECT_FILE) глобальной событийной шины, которое трансформируется из события IPC, присланное из главного процесса Electron. В главном процессе IPC событие отправляется в канал с именем “on-files-select”


Событие ON_SELECT_FILE генерируется в результате открытия диалогового окна и выбора файла для отображения в редакторе. В хуке created() происходит проверка результата выбора файла, и, если файл был выбран, происходит вычленение расширения файла, на основе которого задается параметр language, являющийся индикатором применения стиля подсветки для содержимого. Переменная language – реактивная. При изменении этой переменной, prism-editor автоматически запускает внутренние механизмы применения новой схемы подсветки. Далее, происходит чтение содержимого выбранного файла и занесение его в переменную text. Поскольку переменная text так же является реактивным свойством, prism-editor запускает механизмы отображения содержимого, согласно выбранной схеме синтаксической подсветки.


     2.3 Сборка проекта


Прежде чем запустить Electron приложение, нам необходимо выполнить сборку проекта Webpack’ом. В этом проекте я разделил сборку на 2 ветки: development (webpack.dev.js) и production (webpack.prod.js). webpack.dev.js и webpack.prod.js в процессе сборки объединяются с общим конфигурационным файлом webpack.common.js. Данное разделение очень удобно, когда настройки разных веток сборок имеют общие для всех веток настройки. Для объединения конфигураций я использовал модуль "webpack-merge" из реестра npm. Зависимость этого модуля указана в секции devDependencies в файле «package.json». Каждая из этих конфигурационных веток, в процессе сборки, передаётся как параметр при запуске сборки Webpack’ом (см. секцию scripts файла «package.json».) В моём проекте целевой путь для собранного Webpack’ом приложения разными ветками является одинаковым: path: path.resolve(__dirname, './app'). Отличие между development и production ветками является только то, что production ветка включает в себя дополнительные параметры по оптимизации полученного результата: мнификация + обфускация кода js, минификация css стилей, исключение кода, связанного с отладкой VueJS фреймворка, исключение подсказок и комментариев в собранный бандл (bundle) Webpack’а.


Для запуска сборки проекта в режиме development необходимо перейти в корень проекта и выполнить команду в командной строке:


npm run dev

В этом случае будет выполнена сборка проекта в папку «/app».



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


Для запуска сборки проекта в режиме "production" необходимо перейти в корень проекта и выполнить команду в командной строке:


npm run build


В этом случае будет выполнена сборка проекта в папку «/app» со всеми оптимизациями и Webpack завершит работу.


2.4 Запуск приложения «Поиск»


Для запуска Electron приложения необходимо выполнить команду:


npm start

В результате чего в секции "scripts" выполниться команда:


"start": "electron ."

Точка в конце команды «electron .» говорит процессу Electron «выполнить» файл, который указан в свойстве "main" файла «package.json»



     2.4.1 Поиск теста


Откроем любой текстовый файл в моём приложении «Поиск». Я открыл файл «main.js», являющийся частью моего проекта.


Чтобы выполнить поиск в прочитанном содержимом этого файла, необходимо через главное меню «Поиск» выбрать элемент «Найти» или нажать сочетание клавиш Ctrl+F.



В результате, в верхнем правом углу появится блок ввода поисковой фразы.
(см. изображение ниже.). В этом блоке необходимо напечатать поисковую фразу. В процессе набора текста, справа от сроки ввода, показывается текущее найденное вхождение / из общего количества найденного (1/2). Справа от сроки ввода "<" и ">" можно переходить к предыдущему и следующему найденному вхождению.



Если ни одного вхождения не будет найдено, справа от сроки ввода, будет указано "0/0".


     2.4.2 Блок ввода поисковой фразы


Если попытаться найти вёрстку этого блока, то это получится не с первого раза. Дело в том, что этот блок я стащил применил, как отдельно разработанный open source модуль из реестра npm, который в себе реализует API поиска и подсветки текста в Electron. Данный модуль указан в разделе dependencies файла «package.json» и называется 'electron-find'. Импортируется и инициализируется этот модуль в файле «src/electron.js». При сборке Webpak’ом все необходимые ресурсы для работы этого блока автоматически включаются в проект. Открытие (показ) данного блока происходит по ipc событию 'on-find', которое отправляется из главного процесса Electron в результате нажатия сочетания клавиш Ctrl+F или клике на элементе главного меню «Найти». (см. main.js)


2.5 Отладка приложения «Поиск»


Те, кто хоть как-то касался Web разработки знает, что такое «Инструменты разработчика» имеющиеся в любом браузере. Поскольку Electron основан на Chromium, у нас есть в распоряжении те же инструменты отладки, профилирования, мониторинга и прочее, что и у браузера Google Chrome. Для вызова этих инструментов, нам необходимо в скрипте (main.js), который запускает основной процесс Electron, вызвать метод открывающий стандартный «Dev Tools». Данный метод доступен после создания экземпляра окна (render процесса):


win.webContents.openDevTools();

2.6 Распространение приложение «Поиск»


Для того, чтобы этим приложением смог воспользоваться кто-то другой без определённых навыков разработки и программирования, а также без прочтения выше изложенного материала, необходимо определённым образом подготовить всё что получилось в некий инсталляционный пакет. Для этого в 'devDependencies был добавлен проект 'electron-builder. 'electron-builder — это комплексное решение для упаковки и создания готового к распространению приложения Electron с поддержкой «автоматического обновления». Для работы 'electron-builder требуется указать специальную конфигурацию в файле «package.json». В этом проекте я указал сборку под 64-битную операционную систему Windows:


  "build": {
    "appId": "roman.gavrilow.ru.stext",
    "icon": "app/mainicon.png",
    "win": {
      "target": [
        {
          "target": "nsis",
          "arch": [
            "x64"
          ]
        }
      ]
    }
  },

где:


  • appIdAppUserModelIDs для Windows и CFBundleIdentifier идентификатор пакета для MacOS;
  • icon – Иконка приложения;
  • win – целевая платформа;
  • target – упаковщик/инсталлятор или иное;
  • arch – возможная разрядность;

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


npm run dist

Ниже на изображении можно увидеть результат сборки проекта в установочный дистрибутив.



Так же имеется возможность собрать приложение просто сложив все необходимые файлы в папку. Для этого необходимо перейти в корень проекта и выполнить команду в командной строке:


npm run pack


В результате в папке «dist/win-unpacked» можно будет найти полностью рабочее приложение и необходимые модули и библиотеки.



Если попытаться найти в этом каталоге наше web приложение(файлы), которое собирает Webpack в каталог «/app», то с первого раза это не получится. Дело в том, что electron-builder упаковал приложение «Поиск» (файлы) в .asar архив находящийся в папке resources. Этот архив имеет tar-подобный формат, который объединяет файлы в один общий файл. Electron может читать любые файлы из архива без распаковки всего архива.


В Electron два набора API: Node API, предоставляемый Node.js и Web API, предоставляемый Chromium. Оба API поддерживают чтение файлов из архивов asar:


  • Node API: С помощью специальных патчей в Electron Node API, например, fs.readFile и require обрабатывают архивы asar как виртуальные каталоги, а файлы в нем — как обычные файлы в файловой системе.
  • Web API: В веб-странице файлы в архиве могут быть использованы через протокол file:. Как и в Node API, архивы asar обрабатываются как каталоги, например:
    let response = await this.$http.get('file:///path/to/example.asar/file.txt', parms);

Чтобы получить доступ к файлу «.asar» как к обычному файлу, например, это может понадобиться для проверки контрольной суммы, можно использовать встроенный модуль original-fs, который предоставляет оригинальный интерфейс fs без поддержки обработки asar:


const originalFs = require('original-fs');
originalFs.readFileSync('/path/to/example.asar');

Заключение


Разработка приложения «Поиск» с использованием Web технологий на первый взгляд может показаться сложной и чересчур запутанной, но это окупается тем, что данное приложение сразу может работать на разных платформах и нет каких-либо ограничений по разработке достаточно сложных интерфейсов, анимации и прочее. Но есть и ложка дёгтя – это сам Electron (Chromium). Если не брать в счёт размер получаемого дистрибутива (50 мегабайт инсталляционный дистрибутив; 180 мегабайт – в распакованном виде), то игнорировать объём потребляемой памяти мы не можем



Разработчику Electron приложения не стоит никогда об этом забывать, и стараться всегда делать всевозможные оптимизации (привет Skype). Но есть на рынке достаточно качественные продукты, разработанные на этой платформе (в начале статьи я упоминал ИСР (IDE) — Visual Studio Code).


Подведём итоги.


Используя приложение «Поиск» можно просмотреть и отредактировать любой файл, который может быть автоматически синтаксически подсвечен, основываясь на расширении файла, например, если мы имеем дело с неким кодом или форматом.


Мы можем выполнить поиск текста, используя сочетания клавиш Ctrl+F или через главное меню приложения.


К сожалению, мы не можем достаточно комфортно работать с большими по размеру файлами из-за того, что приложение Electron будет слишком требовательно к оперативной памяти. Это досадное ограничение можно относительно легко обойти путём поблочной загрузки и вывода содержимого файла и при желании применить виртуальный скрол… Также приложение «Поиск» не имеет функции сохранения файла, если содержимое последнего отредактировали. Этот функционал требует доработки.


При разработке столь простого приложения, если бы реально поступила такая задача, я бы не стал использовать этот технологический стек разработки. Я бы выбрал, скорее всего, только C++ или C++ и QT. Если и брать в расчет web технологии при разработки реального кроссплатформенного приложения, то я бы, скорее всего, на том же C++ разработал приложение, которое в себе реализует простейший Web сервер, отдающий статические файлы, и обрабатывающий классические GET и POST запросы. Открыв страничку в любом браузере или реализовав, например, автоматическое открытие страницы при запуске приложения, в браузере по умолчанию можно было отобразить интерфейс приложения.


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


Проект на GitHub:
https://github.com/gewisser/SText




Глоссарий
№ п/п Понятие Определение
1 ИСР (IDE) Интегрированная среда разработки.
2 ПО Программное обеспечение
3 Технологический стек Набор инструментов, применяющийся при работе в проектах и включающий языки программирования, фрэймворки, системы управления базами данных, компиляторы и т. д
4 Кроссплатформенный способность программного обеспечения работать с двумя и более аппаратными платформами и (или) операционными системами
5 Фреймворк (Framework) программная платформа, определяющая структуру программной системы; программное обеспечение, облегчающее разработку и объединение разных компонентов большого программного проекта.
6 Стартап это тип бизнеса, направленный на получение дохода путем реализации принципиально новой идеи.
7 Браузер Программа для поиска и просмотра на экране компьютера информации из компьютерной сети.
8 Рендеринг процесс получения изображения по модели с помощью компьютерной программы
9 Программная платформа среда выполнения, в которой должен выполняться вновь разрабатываемый фрагмент программного обеспечения или объектный модуль с учётом накладываемых этой средой ограничений и предоставляемых возможностей.
10 Движок специализированная программа, обрабатывающая и выполняющая некий код.
11 Десктопный Компьютер или устройство предназначенный для постоянного размещения на столе.
12 Веб-сервер сервер, принимающий HTTP-запросы от клиентов, обычно веб-браузеров, и выдающий им HTTP-ответы, как правило, вместе с HTML-страницей, изображением, файлом, медиа-потоком или другими данными.
13 событийно-ориентированное программирование парадигма программирования, в которой выполнение программы определяется событиями — действиями пользователя (клавиатура, мышь), сообщениями других программ и потоков, событиями операционной системы (например, поступлением сетевого пакета).
14 Асинхронное выполнение кода выполнение процесса в неблокирующем режиме системного вызова, что позволяет потоку программы продолжить обработку. Реализовать асинхронное программирование можно несколькими способами, о которых вы узнаете ниже.
15 Реактивное программирование парадигма программирования, ориентированная на потоки данных и распространение изменений. Это означает, что должна существовать возможность легко выражать статические и динамические потоки данных, а также то, что нижележащая модель исполнения должна автоматически распространять изменения благодаря потоку данных.
16 IPC ( inter-process communication) обмен данными между потоками одного или разных процессов.
17 Командная строка это интерфейс взаимодействия пользователя с компьютером, в котором команды отдаются путем ввода текстовых строк при помощи клавиатуры.
18 система сборки ПО, заключающийся в автоматизации широкого спектра задач, решаемых программистами в их повседневной деятельности.
19 Транспайлер программа (тип компилятора), выполняющая транспиляцию программы
20 Транспиляция преобразование программы, при котором используется исходный код программы, написанной на одном языке программирования в качестве исходных данных, и производится эквивалентный исходный код на другом или таком же но расширенном языке программирования.
21 Загрузчик Webpack представляет собой модуль для Webpack трансформирующий каким либо образом файл вашего проекта.
22 Плагин Webpack представляет собой модуль для Webpack расширяющий его функциональность.
23 Шаблонизатор программное обеспечение, позволяющее использовать html-шаблоны для генерации конечных html-страниц
24 Препроцессинг принятие данных на входе и выдача данных, предназначенных для входа другой программы (например, компилятора)
25 Компиля́ция сборка программы, включающая трансляцию всех модулей программы, написанных на одном или нескольких исходных языках программирования высокого уровня, в эквивалентные программные модули на более низком уровне
26 мутация данных это изменение существующих данных или структуры, которая их в себе хранит. Иммутабельность же, в свою очередь, предполагает создание копии существующих данных или структуры, когда необходимы изменения, и добавление этих изменений туда.
27 JSON JavaScript Object Notation — простой формат обмена данными, удобный для чтения и написания как человеком, так и компьютером. Он основан на подмножестве языка программирования JavaScript, определенного в стандарте ECMA-262 3rd Edition — December 1999.
28 хуки (hooks) технология, позволяющая изменить стандартное поведение тех или иных компонентов информационной системы.
29 Глобальная событийная шина Отдельно созданный экземпляр Vue для организации межкомпонентной передачи данных или событий.
30 web приложение Web страница, открытая в браузере где реализована вся логика работы с интерфейсом и отображением данных.
31 API Application Programming Interface — интерфейс, который позволяет разработчикам использовать готовые блоки или функционал для построения приложения.
32 контрольная сумма некоторое значение, рассчитанное по набору данных путём применения определённого алгоритма и используемое для проверки целостности данных при их передаче или хранении.

Теги:
Хабы:
Всего голосов 9: ↑5 и ↓4+1
Комментарии8

Публикации

Истории

Работа

Ближайшие события

One day offer от ВСК
Дата16 – 17 мая
Время09:00 – 18:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург
Summer Merge
Дата28 – 30 июня
Время11:00
Место
Ульяновская область