создание веб приложения на javascript
Как быстро создать десктопное приложение на HTML, CSS и JavaScript
Можно ли использовать HTML, CSS и JavaScript для создания десктопных приложений?
В этой статье мы сосредоточимся в основном на том, как Electron можно использовать для создания десктопных приложений с использованием веб-технологий.
Electron
Electron может быть использован для создания десктопных приложений, также эти приложения будут мультиплатформенными — Windows, Mac, Linux и другие.
Electron объединяет Chromium и Node.js в одну среду исполнения. Это позволяет нам запускать код HTML, CSS и JavaScript в виде десктопного приложения.
Electron Forge
Если Electron используется напрямую, то перед сборкой приложения потребуется определённая ручная настройка. Также, если вы хотите использовать Angular, React, Vue или любой другой фреймворк или библиотеку, вам нужна будет ручная настройка.
Electron Forge значительно упрощает все вышеперечисленное.
Он предоставляет шаблонные приложения с Angular, React, Vue и другими фреймворками, что позволяет избежать дополнительных танцев с бубном.
Также он обеспечивает простоту сборки и упаковки приложения. В нём есть множество других функций, которые можно найти в документации.
Предварительная подготовка
Убедитесь, что у вас установлен Node.js. Если нет, то его можно скачать отсюда. Установите Electron Forge глобально, используя следующую команду:
Начнём с приложения
Используйте следующую команду для создания вашего приложения:
simple-desktop-app-electronicjs — это название приложения.
Потребуется некоторое время, чтобы команда, указанная выше, отработала. После завершения предыдущего процесса запустите приложение с помощью следующих команд:
Это должно открыть окно как на скрине ниже:
Разберёмся в структуре и коде
Приложение имеет определенную структуру папок. Здесь я перечислю некоторые важные моменты в этой структуре папок.
package.json
Содержит информацию о приложении, которое вы создаете, все зависимости, необходимые для приложения, и несколько скриптов. Некоторые из скриптов уже предварительно настроены, но вы также можете добавлять новые.
Путь config.forge содержит все конфигурации конкретно для Electron. Например, make-target используется для указания целевых файлов для различных платформ, таких как Windows, Mac или Linux.
src/index.js
Основной процесс нужен для отображения элементов интерфейса. Это делается путем создания страниц. Каждая созданная страница выполняется в процессе, называемом процессом отрисовки.
Главный процесс и процесс отрисовки
Любое приложение может иметь только один главный процесс, но много процессов визуализации.
Также возможно взаимодействие между главным процессом и процессом отрисовки. Однако, я не буду останавливаться на этом в текущей статье.
abcd.html показан в качестве второй веб-страницы в приведенной выше архитектуре. Но в нашем коде у нас не будет второй веб-страницы.
src/index.html
Код в index.js с пояснениями
app используется для управления жизненным циклом событий приложения. Приведенный выше фрагмент кода говорит, что, когда приложение будет готово, нужно загрузить первое окно.
Точно так же app может использоваться для выполнения других действий с различными событиями. Например, его можно использовать для выполнения некоторых действий непосредственно перед закрытием приложения и так далее.
Создадим десктопное приложение конвертера температур
Давайте воспользуемся тем же приложением, которое мы создали ранее, и немного изменим его, чтобы создать приложение конвертера температуры.
Сначала давайте установим Bootstrap с помощью следующей команды:
Скопируйте следующий код в src/index.html:
Приведенный выше код выполняет следующие действия:
Функция celciusToFahrenheit() считывает значение в текстовом поле «По Цельсию», преобразует его в градусы Фаренгейта и записывает новую температуру в текстовое поле «По Фаренгейту».
Функция fahrenheitToCelcius() делает ровно наоборот.
Запускаем приложение
Запустите приложение, используя следующую команду:
Должно открыться следующее окно. Попробуйте ввести разные значения в инпуты.
Десктопные приложения на JavaScript. Часть 1
Ни для кого не секрет, что в наше время JavaScript стал одним из самых популярных языков программирования. В далекие 90е годы, в момент зарождения языка, когда он был создан с единственной целью добавить интерактивность веб страницам и улучшить процесс взаимодействия с пользователем, кто бы мог подумать, что он достигнет столь небывалых высот. Ведь сейчас на нем можно делать практически все что угодно. Хотите написать сайт: и бэкэнд и фронтэнд на JavaScript? пожалуйста! Хотите написать мобильное приложение на JavaScript? нет проблем. Программируете микроконтроллер – и тут вам на помощь придет JavaScript.
Есть конечно небольшие минусы в подходе использования JavaScript везде, но если поразмыслить, то сколько времени и сил можно сэкономить, изучив всего лишь одни язык, особенно, если то же самое приложение должно работать на разных платформах. Разных платформах говорите? Хм… Точно – разных платформах – теперь JS может позволить себе десктопные приложения для Windows, Linux, Mac, как спросите вы? Ответ прост: встречайте – NW.js.
По первым буквам можно прочитать – Node.js + Webkit, если данные понятия вам пока не знакомы, то скоро вы поймете о чем идет речь.
Node.js – программная платформа, основанная на движке V8, который транслирует наш скрипт в машинный код. Данная платформа была создана в 2009 году преимущественно для работы с бэкэндом сайтов.
WebKit — свободный движок, разработанный компанией Apple. Впервые был анонсирован в составе Safari в 2003 году
Итак, коду, написанному на JS для данной технологии, будут доступны как Node.js модули, так и стандартный браузерный API (соответственно WebKit)
Быстрый старт
Все это конечно хорошо, но с чего же начать? На github можно найти и скачать репозиторий с исходным кодом. Так же здесь можно найти прямые ссылки для скачивания под ту платформу, на которой будет вестись разработка. Помимо прочего нам понадобится установленная node.js.
После того, как необходимое ПО скачано и установлено, вы написали свое приложение на любимом JS (как это сделать читайте далее) и локализовали все в одну папку. Полдела сделано, теперь остается самое сложное и долгое – упаковать все в один файл и подготовить для распространения. Для упрощения вы можете воспользоваться готовыми библиотеками, например nw-builder. Установка библиотеки не составит труда, если вы уже работали с node.js. Как известно, в состав node.js входит менеджер пакетов npm, с которым нужно работать из командной строки. Для того, чтобы поставить какую-либо библиотеку, необходимо выполнить команду:
Обратите внимание, что библиотеку можно ставить, как локально, так и глобально, для локальной установки используйте опцию —save-dev, для глобальной -g. Таким образом поставим наш сборщик для NW.js глобально, выполнив команду:
Для того, чтобы собрать наше приложение, необходимо выполнить команду (с большим количеством опций можно ознакомиться в документации):
В качестве имени платформы могут быть следующие значения: win32, win64, osx32, osx64, linux32, linux64.
Во время разработки нет нужды каждый раз собирать приложение, можно просто запустить его как есть и оно откроется в отдельном окне. Для этого нужно запустить приложение nw.exe из командной строки и передать в качестве параметров путь к папке с вашим приложением. Кроме того, если вы работаете под Windows, можно просто методом drag-n-drop перетащить папку с исходным кодом приложения на JS (обратите внимание, что именно папку целиком) в nw.exe.
Hello, world!
Теперь, когда вы знаете, как запустить приложение, как собрать его в один файл, давайте напишем что-нибудь. По традиции знакомство с новой платформой начинается с написания приложения Hello, world.
Для данного приложения, нам даже не понадобится JavaScript, только HTML. Создадим папку с названием HelloWorld. Поместим внутрь файл index.html со следующей разметкой:
Кроме того для каждого приложения под NW.js необходим файл, который обязательно должен называться package.json. Из него будет браться информация для построения приложения. Создадим простейший вариант файла и поместим в папку HelloWorld. Итак:
Содержимое файла понятно без пояснений (обратите внимание, что обязательные поля только main и name). В main необходимо записать файл с разметкой, который будет являться точкой входа в приложение. Секция window настраивает параметры окна (в данном случае мы отключаем панель инструментов и задаем размеры окна 500×200).
Кроме того, можно настроить такие поля как (за полным списком опций обращайтесь в документацию):
Приложение написано, но в нем всего один div элемент и совсем нет логики, а что делать, если у нас богатая на элементы разметка и сложная логика? На помощь к нам приходит элемент конфигурационного файла toolbar, который мы установили в false. Для того, чтобы сделать доступными средства отладки, необходимо установить toolbar в true. Проделав это при запуске приложения мы получим следующее окно:
После нажатия на кнопку в верхнем правом углу откроется еще одно окно, в котором будут отображены знакомые инструменты разработчика:
Работа с нативными контролами
NW.js позволяет работать с нативными контролами. Рассмотрим работу на примере меню. Для работы с нативным UI контролами в nw.js необходимо использовать модуль nw.gui, который можно подключить следующим образом:
Общий шаблон для использования контролов:
Таким образом для создания элементов меню можно воспользоваться следующей конструкцией:
Кроме того любые свойства созданного нами объекта можно легко изменить стандартными конструкциями JS, например так:
Меню создано, теперь нужно его заполнить, для манипуляции дочерними элементами существуют методы:
Кроме того для более гибкого добавления элементов в menu можно воспользоваться методом insert, в параметрах которого необходимо передать MenuItem и номер позиции, куда его вставить (позиция перед первым элементом соответствует 0).
Для доступа к созданным элементам можно использовать свойство items:
Обратите внимание, что нельзя напрямую создавать элементы:
Самое главное при работе с нативными контролами, это помнить, что любая ошибка при работе с ними может привести к краху всего приложения, поэтому необходимо быть крайне внимательными и по возможности при удалении элементов, также присваивать переменной значение null. Таким образом для удаления контрола, можно выполнить следующее:
Для более удобной работы с контролами, они унаследованы от EventEmitter, поэтому хорошая новость в том, что мы можем легко работать с событиями, например так:
Меню было создано, но если запустить приложение, то никакого меню вы не увидите. Для отображения меню существует метод popup, в параметрах которого необходимо передать координаты для отображения меню.
Для демонстрации основных возможностей меню добавьте следующий скрипт к созданному ранее проекту Hello, world:
После запуска приложения, мы можем увидеть созданное контекстное меню для body. Таким образом, мы можем определить контекстное меню для любого элемента.
Итак, теперь кроссплатформенные приложения может создавать каждый, но за все нужно платить. В данном случае мы жертвуем как скоростью, так и занимаемым объемом памяти (собранное приложение получается достаточно большим, более 50 Мб). Список приложений, созданных, используя данную технологию можно найти на github.
Во второй части статьи мы рассмотрим технологию более подробно.
Создайте веб-приложение с помощью современного JavaScript и веб-компонентов
JavaScript в браузере эволюционировал. Разработчики, которые хотят воспользоваться новейшими функциями, могут отказаться от фреймворка с меньшими хлопотами. Параметры, обычно зарезервированные для интерфейсных фреймворков, такие как компонентный подход, теперь возможны в простом старом JavaScript.
В этом дубле я продемонстрирую все новейшие функции JavaScript, используя пользовательский интерфейс, который содержит данные об авторе с сеткой и фильтром поиска. Чтобы не усложнять, как только техника будет представлена, я перейду к следующей технике, чтобы не вдаваться в подробности. По этой причине в пользовательском интерфейсе будет опция «Добавить» и выпадающий фильтр поиска. Модель автора будет иметь три поля: имя, адрес электронной почты и необязательную тему. Валидация формы будет включена в основном для того, чтобы продемонстрировать эту безфреймворковую технику, но не до конца.
Когда-то смелый язык вырос с множеством современных функций, таких как прокси, импорт / экспорт, дополнительный оператор цепочки и веб-компоненты. Это идеально подходит для Jamstack, потому что приложение обрабатывает на клиенте с помощью HTML и обычного JavaScript.
Я оставлю API, чтобы сосредоточиться на приложении, но я укажу, где эта интеграция может происходить внутри приложения.
Getting Started
Приложение представляет собой типичное приложение JavaScript с двумя зависимостями: http-сервер и Bootstrap. Код будет работать только в браузере, поэтому нет другой серверной части, кроме одной для размещения статических ресурсов. Код размещен на GitHub, и вы можете с ним поиграть.
Предполагая, что на вашем компьютере установлена последняя версия Node LTS :
В результате должен получиться единственный package.jsonфайл, в который будут помещены зависимости.
Чтобы установить две зависимости:
Откройте package.jsonфайл и установите точку входа через «start»: «http-server«под scripts. Идите вперед и запустите приложение через npm start, которое станет http://localhost:8080/доступным для браузера. Любой index.htmlфайл, помещенный в корневую папку, автоматически размещается на HTTP-сервере. Все, что вам нужно сделать, это обновить страницу, чтобы получить самые свежие данные.
Структура папок выглядит так:
Вот для чего предназначена каждая папка:
Чтобы создать папки и файлы в каждой папке, выполните следующее:
Интегрировать веб-компоненты
Вкратце, веб-компоненты — это настраиваемые HTML-элементы. Они определяют настраиваемый элемент, который может быть помещен в разметку, и объявляют метод обратного вызова, который отображает компонент.
Вот краткое изложение настраиваемого веб-компонента:
Если вы чувствуете, что вам нужно более мягкое введение в веб-компоненты, ознакомьтесь со статьей MDN. Сначала они могут показаться волшебными, но хорошее понимание метода обратного вызова делает это совершенно очевидным.
На главной index.htmlстатической странице объявляются веб-компоненты HTML. Я буду использовать Bootstrap для стилизации HTML-элементов и добавления index.jsресурса, который станет основной точкой входа приложения и шлюзом в JavaScript.
Откройте index.htmlфайл и вставьте его на место:
Обратите особое внимание на scriptтег с typeатрибутом, установленным на module. Это то, что разблокирует импорт / экспорт в обычном JavaScript в браузере. templateТег с idопределяет HTML — элементы, которые позволяют веб — компоненты. Я распался приложение на три основных компоненты: html-app, author-formи author-grid. Поскольку в JavaScript еще ничего не определено, приложение будет отображать панель навигации без каких-либо пользовательских тегов HTML.
Чтобы начать легко, поместите это в ObservableElement.js. Это родительский элемент для всех компонентов автора:
Затем определите html-appкомпонент в App.js:
Обратите внимание на использование export defaultдля объявления классов JavaScript. Эту возможность я включил с помощью moduleтипа, когда ссылался на основной файл сценария. Чтобы использовать веб-компоненты, унаследуйте метод класса HTMLElementи определите его connectedCallback. Об остальном позаботится браузер. Я использую requestAnimationFrameдля рендеринга основного шаблона перед следующей перерисовкой в браузере.
Это распространенный метод, который вы увидите с веб-компонентами. Сначала возьмите шаблон по идентификатору элемента. Затем клонируйте шаблон через cloneNode. Наконец, appendChildновое contentв DOM. Если вы столкнетесь с какими-либо проблемами, когда веб-компоненты не отображаются, убедитесь, что клонированный контент сначала был добавлен в DOM.
Затем определите AuthorGrid.jsвеб-компонент. Этот будет следовать аналогичному шаблону и немного манипулировать DOM:
Взгляните на importоператор, потому что он вводит зависимость с полным расширением в имени файла. Если вы привыкли к разработке Node, то в этом она отличается от реализации в браузере, которая соответствует стандарту, где для этого требуется расширение файла, например.js. Учитесь у меня и обязательно ставьте расширение файла при работе в браузере.
Далее, AuthorForm.jsкомпонент состоит из двух основных частей: рендеринга HTML и подключения событий элемента к форме.
Чтобы отобразить форму, откройте AuthorForm.js:
Он focusнаправляет пользователя, чтобы начать вводить текст на первом элементе ввода, доступном в форме. Обязательно ставьте DOM селекторы послеappendChild, так как в противном случае этот метод не будет работать. resetFormНе используется прямо сейчас, но сбросит состояние формы, когда пользователь нажимает клавишу Enter.
Подключите события через addEventListenerдобавление этого кода внутри connectedCallbackметода. Это можно добавить в самый конец connectedCallbackметода:
Это типичные прослушиватели событий, которые прикрепляются к this.formэлементу в DOM. changeСобытие делегации использует событие для прослушивания всех событий изменения в форме, но предназначается только select.searchэлемент. Это эффективный способ делегировать одно событие как можно большему количеству целевых элементов в родительском элементе. Если это сделано, ввод чего-либо в форме и нажатие Enter сбрасывает форму обратно в нулевое состояние.
Чтобы эти веб-компоненты отображались на клиенте, откройте index.jsи вставьте это:
Не стесняйтесь обновлять страницу в браузере и поиграть с пользовательским интерфейсом. Откройте инструменты разработчика и просматривайте сообщения консоли, когда вы нажимаете и вводите форму. Нажатие Tabклавиши должно помочь вам перемещаться между элементами ввода в документе HTML.
Validate the Form
Поигравшись с формой, вы можете заметить, что она принимает произвольный ввод, когда требуются и имя, и адрес электронной почты, а тема является необязательной. Подход без фреймворка может представлять собой комбинацию проверки HTML и небольшого количества JavaScript. К счастью, Bootstrap несколько упрощает эту задачу, добавляя / удаляя имена классов CSS через classListвеб-API.
Внутри AuthorForm.jsкомпонента найдите console.logв Enterключевом обработчике событий, найдите журнал с «Pressed Enter» и поместите его прямо над ним:
Затем определите isValidметод класса в AuthorForm. Это может выходить за рамки resetFormметода:
В обычном JavaScript при вызове checkValidityиспользуется встроенный валидатор HTML, потому что я пометил элемент ввода с помощью type=»email«. Чтобы проверить наличие обязательных полей, простая проверка правдивости помогает с помощью i.value. classListВеб — API добавляет или удаляет имена классов CSS, поэтому моделирование Bootstrap может выполнять свою работу.
А теперь попробуйте еще раз. Попытка ввести недопустимые данные теперь помечается, а действительные данные сбрасывают форму.
Наблюдаемые
Пришло время для мяса (или картошки для моих друзей-вегетарианцев) этого подхода, потому что веб-компоненты и обработчики событий могут только увести меня. Чтобы сделать это приложение управляемым состоянием, мне понадобится способ отслеживать изменения состояния пользовательского интерфейса. Оказывается, наблюдаемые объекты идеально подходят для этого, потому что они могут запускать обновления пользовательского интерфейса при изменении состояния. Думайте о наблюдаемых как о модели sub / pub, где подписчики отслеживают изменения, а издатель запускает те изменения, которые произошли в состоянии пользовательского интерфейса. Это упрощает объем кода push и pull, необходимый для создания сложных и захватывающих пользовательских интерфейсов без какой-либо инфраструктуры.
Откройте obserable.jsфайл modelи вставьте его:
Поначалу это может показаться пугающим, но он делает две вещи: захват установщика для перехвата мутаций и добавление слушателей. В ES6 + Proxyкласс включает прокси, который обтекает initialStateобъект. Это может перехватывать базовые операции, подобные этому setметоду, который выполняется при изменении объекта. Возврат trueв сеттере позволяет внутреннему механизму JavaScript узнать, что мутация прошла успешно. В Proxyустанавливает объект обработчика, где такие как ловушки setполучить определены. Поскольку меня интересуют только мутации объекта состояния, у setнего есть ловушка. Все остальные функции, такие как чтение, перенаправляются непосредственно в объект исходного состояния.
Слушатели хранят список подписанных обратных вызовов, которые хотят получать уведомления о мутациях. Обратный вызов выполняется один раз после добавления слушателя и возвращает прослушивающий обратный вызов для использования в будущем.
Функции freezeи cloneDeepсозданы для предотвращения дальнейших мутаций базового объекта состояния. Это сохраняет состояние пользовательского интерфейса более предсказуемым и в некоторой степени не имеющим состояния, поскольку данные перемещаются только в одном направлении.
Теперь перейдите к actions.jsфайлу и вставьте его на место:
Это тестируемый объект JavaScript, который выполняет фактические изменения состояния. Для краткости я откажусь от написания модульных тестов, но оставлю это в качестве упражнения для читателей.
Чтобы запускать мутации из веб-компонентов, их необходимо зарегистрировать в глобальном window.applicationContextобъекте. Это делает этот объект состояния с изменениями доступным для остальной части приложения.
Откройте основной index.jsфайл и добавьте его прямо над местом, где я зарегистрировал настраиваемые элементы:
Доступны два объекта: прокси observableStateи объект actionsс мутациями. Программа INITIAL_STATEзагружает приложение с исходными данными. Это то, что устанавливает начальное нулевое состояние конфигурации. Мутации действия принимают наблюдаемое состояние и запускают обновления для всех слушателей, внося изменения в observableStateобъект.
Поскольку мутации еще не подключены к веб-компонентам applicationContext, пользовательский интерфейс не отслеживает никаких изменений. Веб-компонентам потребуются атрибуты HTML для изменения и отображения данных состояния. Вот что будет дальше.
Observed Attributes
Для веб-компонентов изменения состояния можно отслеживать с помощью веб-API атрибутов. Это getAttribute, setAttributeи hasAttribute. С этим арсеналом более эффективно сохранять состояние пользовательского интерфейса в DOM.
Взломайте ObservableElement.jsи выпотрошите его, заменив этим кодом:
Я специально использовал в current-filterатрибуте змеиный кожух. Это связано с тем, что веб-API атрибутов поддерживает только имена в нижнем регистре. Геттер / сеттер выполняет сопоставление между этим веб-API и тем, что ожидает класс, что является случаем верблюда.
connectAttributesМетод в веб — компонент добавляет свой собственный слушатель для отслеживания состояния мутаций. Есть attributeChangedCallbackдоступный, который срабатывает при изменении атрибута, а веб-компонент обновляет атрибут в DOM. Этот обратный вызов также вызывает, updateContentчтобы сообщить веб-компоненту об обновлении пользовательского интерфейса. Геттер / сеттер ES6 + объявляет те же свойства, что и в объекте состояния. Это то, что делает this.authors, например, доступным для веб-компонента.
Обратите внимание на использование constructor.observedAttributes. Это настраиваемое статическое поле, которое я могу объявить сейчас, чтобы родительский класс ObservableElementмог отслеживать, какие атрибуты важны для веб-компонента. Благодаря этому я могу выбирать, какая часть модели состояния имеет отношение к веб-компоненту.
Я воспользуюсь этой возможностью, чтобы конкретизировать остальную часть реализации, чтобы отслеживать и изменять состояние с помощью наблюдаемых в каждом веб-компоненте. Это то, что заставляет пользовательский интерфейс «оживать» при изменении состояния.
Вернитесь AuthorForm.jsи внесите эти изменения. Комментарии к коду скажут вам, где его разместить (или вы можете проконсультироваться с репозиторием ):
В Jamstack вам может потребоваться вызвать внутренний API для сохранения данных. Я рекомендую использовать вспомогательные методы для этих типов вызовов. Как только постоянное состояние возвращается из API, оно может быть изменено в приложении.
Наконец, найдите AuthorGrid.jsи подключите наблюдаемые атрибуты (последний файл находится здесь ):
Каждый веб-компонент может отслеживать различные атрибуты в зависимости от того, что отображается в пользовательском интерфейсе. Это хороший чистый способ разделения компонентов, поскольку он имеет дело только с собственными данными состояния.
Попробуйте это в браузере. Взломайте инструменты разработчика и проверьте HTML. Вы увидите атрибуты, установленные в DOM, например current-filter, в корне веб-компонента. Когда вы щелкаете и нажимаете Enter, обратите внимание, что приложение автоматически отслеживает мутации состояния в DOM.
Gotchas
Для получения дополнительной информации не забудьте оставить инструменты разработчика открытыми, перейдите в отладчик JavaScript и найдите AuthorGrid.js. Затем установите точку останова в любом месте updateContent. Выберите поисковый фильтр. Заметили, что браузер повторяет этот код более одного раза? Это означает, что код, обновляющий пользовательский интерфейс, запускается не один раз, а каждый раз при изменении состояния.
Это из-за этого кода, который находится в ObservableElement:
В настоящее время существует ровно два слушателя, которые срабатывают при изменении состояния. Если веб-компонент отслеживает более одного свойства состояния, например this.authors, это вызывает гораздо больше обновлений пользовательского интерфейса. Это приводит к неэффективному обновлению пользовательского интерфейса и может вызвать задержку с достаточным количеством слушателей и изменениями в DOM.
Чтобы исправить это, откройте ObservableElement.jsи вернитесь к установщикам атрибутов HTML:
Это добавляет уровень защитного программирования для обнаружения изменений атрибутов. Когда веб-компонент понимает, что ему не нужно обновлять пользовательский интерфейс, он пропускает установку атрибута.
Теперь вернитесь в браузер с точкой останова, состояние обновления должно произойти updateContentтолько один раз.
Заключение
Приложения без фреймворка через веб-компоненты и наблюдаемые объекты позволяют создавать многофункциональные пользовательские интерфейсы без каких-либо зависимостей. Это делает полезную нагрузку приложения легкой и быстрой для клиентов.