Проектирование и создание прогрессивного веб-приложения без фреймворка (часть 1)
Опубликовано: 2022-03-10Как на самом деле работает веб-приложение? Я не имею в виду с точки зрения конечного пользователя. Я имею в виду в техническом смысле. Как на самом деле работает веб-приложение? Что сбивает с толку? Как правильно структурировать приложение без шаблонного кода? В частности, клиентское приложение, где вся логика выполняется на устройстве конечного пользователя. Как данные управляются и манипулируются? Как заставить интерфейс реагировать на изменения данных?
Это те вопросы, которые легко обойти или полностью проигнорировать с помощью фреймворка. Разработчики обращаются к чему-то вроде React, Vue, Ember или Angular, следуя документации, чтобы приступить к работе и уйти. Эти проблемы решаются набором трюков фреймворка.
Это может быть именно то, как вы хотите. Возможно, это разумный поступок, если вы хотите построить что-то на профессиональном уровне. Однако, абстрагировавшись от магии, вы никогда не узнаете, как на самом деле выполняются трюки.
Разве ты не хочешь знать, как делаются трюки?
Я сделал. Итак, я решил попробовать создать базовое клиентское приложение без фреймворка, чтобы понять эти проблемы для себя.
Но я немного забегаю вперед; сначала немного предыстории.
Прежде чем начать это путешествие, я считал себя очень опытным в HTML и CSS, но не в JavaScript. Поскольку я чувствовал, что решил к своему удовлетворению самые большие вопросы, которые у меня были относительно CSS, следующей задачей, которую я поставил перед собой, было понимание языка программирования.
Дело в том, что я был относительно новичком в JavaScript. И, кроме взлома PHP Wordpress, у меня не было знакомства или обучения какому-либо другому языку программирования.
Позвольте мне уточнить это утверждение «начинающего уровня». Конечно, я мог бы заставить интерактивность работать на странице. Переключать классы, создавать узлы DOM, добавлять и перемещать их и т. д. Но когда дело дошло до организации кода для чего-то еще, я был совершенно невежественен. Я не был уверен в создании чего-либо близкого к приложению. Я понятия не имел, как определить набор данных в JavaScipt, не говоря уже о том, чтобы управлять им с помощью функций.
У меня не было понимания «шаблонов проектирования» JavaScript — устоявшихся подходов к решению часто встречающихся проблем с кодом. Я определенно не понимал, как подходить к фундаментальным решениям по дизайну приложений.
Вы когда-нибудь играли в Top Trumps? Что ж, в редакции для веб-разработчиков моя карточка выглядела бы примерно так (баллы из 100):
- CSS: 95
- Скопируйте и вставьте: 90
- Линия роста волос: 4
- HTML: 90
- JavaSript: 13
Помимо желания испытать себя на техническом уровне, мне также не хватало дизайнерских способностей.
Поскольку в последнее десятилетие я почти исключительно кодировал проекты других людей, мои навыки визуального дизайна не испытывали особых проблем с конца нулевых. Размышляя над этим фактом и моими жалкими навыками JavaScript, я культивировал растущее чувство профессиональной неадекватности. Пришло время исправить мои недостатки.
В моей голове возникла личная задача: спроектировать и создать клиентское веб-приложение на JavaScript.
На обучение
Никогда не было более отличных ресурсов для изучения компьютерных языков. В частности JavaScript. Тем не менее, мне потребовалось некоторое время, чтобы найти ресурсы, которые объясняли вещи таким образом, который щелкал. Мне очень помогли книги Кайла Симпсона «Вы не знаете JS» и «Красноречивый JavaScript» Марийна Хавербеке.
Если вы начинаете изучать JavaScript, вам обязательно нужно будет найти своих гуру; люди, чей метод объяснения работает на вас.
Первая ключевая вещь, которую я усвоил, заключалась в том, что бессмысленно пытаться учиться у учителя/ресурса, который не объясняет вещи так, как вы их понимаете. Некоторые люди смотрят на примеры функций с foo
и bar
и сразу же понимают смысл. Я не из тех людей. Если вы тоже, не думайте, что языки программирования не для вас. Просто попробуйте другой ресурс и продолжайте применять навыки, которые вы изучаете.
Также не факт, что вам понравится какой-либо момент озарения, когда все вдруг «щелкнет»; как кодовый эквивалент любви с первого взгляда. Скорее всего, потребуется много настойчивости и значительное применение ваших знаний, чтобы чувствовать себя уверенно.
Как только вы почувствуете себя хоть немного компетентным, попытка применить полученные знания научит вас еще большему.
Вот некоторые ресурсы, которые я нашел полезными на этом пути:
- Канал Fun Fun Fun на YouTube
- Кайл Симпсон Курсы множественного числа
- JavaScript30.com Уэса Боса
- Красноречивый JavaScript от Марин Хавербеке
Правильно, это почти все, что вам нужно знать о том, почему я пришел к этому моменту. Слон сейчас в комнате есть, почему бы не использовать фреймворк?
Почему бы не реагировать, Ember, Angular, Vue и др.
Хотя ответ был указан в начале, я думаю, что вопрос о том, почему фреймворк не использовался, нуждается в расширении.
Существует множество высококачественных, хорошо поддерживаемых фреймворков JavaScript. Каждый из них специально разработан для создания клиентских веб-приложений. Как раз то, что я хотел построить. Я прощаю вас за то, что вы удивляетесь очевидному: почему бы не использовать его?
Вот моя позиция по этому поводу. Когда вы учитесь использовать абстракцию, в первую очередь вы изучаете именно абстракцию. Я хотел изучить вещь, а не абстракцию вещи.
Я помню, как в свое время изучал jQuery. В то время как прекрасный API позволил мне сделать манипуляции с DOM проще, чем когда-либо прежде, без него я стал бессилен. Я даже не мог переключать классы элемента, не нуждаясь в jQuery. Задайте мне базовую интерактивность на странице без поддержки jQuery, и я спотыкался в своем редакторе, как стриженый Самсон.
Совсем недавно, когда я пытался улучшить свое понимание JavaScript, я попытался немного разобраться в Vue и React. Но, в конце концов, я так и не понял, где заканчивается стандартный JavaScript и начинается React или Vue. Я считаю, что эти абстракции гораздо более ценны, когда вы понимаете, что они делают для вас.
Поэтому, если я собирался чему-то научиться, я хотел понять основные части языка. Таким образом, у меня были некоторые передаваемые навыки. Я хотел сохранить что-то, когда текущая версия структуры месяца была отброшена для следующей «горячей новинки».
Хорошо. Теперь мы поняли, почему создавалось это приложение, а также, нравится нам это или нет, как оно должно было быть сделано.
Давайте перейдем к тому, что это должно было быть.
Идея приложения
Мне нужна была идея приложения. Ничего слишком амбициозного; У меня не было иллюзий относительно создания собственного бизнеса или участия в Dragon's Den — моей основной целью было изучение JavaScript и основ приложений.
Приложение должно было быть чем-то, что у меня было шансов реализовать технически и сделать приличную дизайнерскую работу вдобавок.
Касательное время.
Вне работы я организую и играю в мини-футбол, когда могу. Мне, как организатору, трудно мысленно отметить, кто прислал мне сообщение о том, что они играют, а кто нет. Обычно для игры требуется 10 человек, 8 на пике. В списке около 20 человек, которые могут или не могут играть в каждую игру.
Идея приложения, на которой я остановился, заключалась в том, что она позволяла выбирать игроков из списка, давая мне возможность подсчитать, сколько игроков подтвердили, что они могут играть.
По мере того, как я думал об этом больше, я чувствовал, что могу немного расширить масштаб, чтобы его можно было использовать для организации любой простой командной деятельности.
По общему признанию, я вряд ли придумал Google Earth. Однако у него были все основные проблемы: дизайн, управление данными, интерактивность, хранение данных, организация кода.
С точки зрения дизайна, я бы не беспокоился ни о чем, кроме версии, которая могла бы работать и хорошо работать на экране просмотра телефона. Я бы ограничил задачи дизайна решением проблем только на маленьких экранах.
Основная идея, безусловно, опиралась на приложения в стиле «дело», среди которых было множество существующих примеров, на которые можно было взглянуть для вдохновения, и в то же время они имели достаточно различий, чтобы обеспечить некоторые уникальные проблемы дизайна и кодирования.
Предполагаемые функции
Первоначальный маркированный список функций, которые я намеревался разработать и закодировать, выглядел так:
- Поле ввода для добавления людей в список;
- Возможность установить для каждого человека статус «вход» или «выход»;
- Инструмент, который разбивает людей на команды, по умолчанию 2 команды;
- Возможность удалить человека из реестра;
- Некоторый интерфейс для «инструментов». Помимо разделения, доступные инструменты должны включать возможность загрузки введенных данных в виде файла, загрузки ранее сохраненных данных и удаления всех игроков за один раз;
- Приложение должно отображать текущий подсчет количества людей, которые «в сети»;
- Если для игры не выбраны люди, разделитель команд должен быть скрыт;
- Платный режим. Переключатель в настройках, который позволяет «входящим» пользователям иметь дополнительный переключатель, показывающий, заплатили они или нет.
В начале это то, что я считал характеристиками минимально жизнеспособного продукта.
Дизайн
Дизайн начинался на клочках бумаги. Было поучительно (читай: сокрушительно) узнать, сколько идей, которые были невероятными в моей голове, оказались смехотворными, когда подверглись даже скудному анализу, обеспечиваемому карандашным рисунком.
Поэтому многие идеи были быстро исключены, но оборотная сторона заключалась в том, что наброски одних идей неизменно приводили к другим идеям, которые я никогда бы иначе не рассмотрел.
Теперь дизайнеры, читающие это, вероятно, скажут: «Да, конечно», но для меня это было настоящим откровением. Разработчики привыкли видеть проекты более поздних стадий, редко видя все заброшенные этапы на пути до этого момента.
Однажды довольный чем-то вроде карандашного рисунка, я пытался воссоздать его в пакете дизайна Sketch. Подобно тому, как идеи отпадали на стадии бумаги и карандаша, столько же не смогли пройти через следующую стадию верности Sketch. Те, которые, казалось, выдержали роль артбордов в Sketch, затем были выбраны в качестве кандидатов для кодирования.
В свою очередь, я обнаружил, что когда эти кандидаты были встроенным кодом, процент также не работал по разным причинам. Каждый шаг верности предъявлял новые требования к дизайну, которые либо сдавались, либо терпели неудачу. А неудача в прямом и переносном смысле вернула бы меня к чертежной доске.
Таким образом, в конечном итоге дизайн, который я получил, немного отличается от того, который у меня был изначально в Sketch. Вот первые макеты Sketch:
Даже тогда я не был в заблуждении; это был базовый дизайн. Тем не менее, в этот момент у меня было что-то, в чем я был относительно уверен, что оно могло бы работать, и я чуть не пожевал, чтобы попытаться создать это.
Технические требования
Имея некоторые первоначальные требования к функциям и базовое визуальное направление, пришло время подумать о том, чего следует достичь с помощью кода.
Хотя общепринятая мудрость подсказывает, что создавать приложения для устройств iOS или Android можно с помощью нативного кода, мы уже установили, что мое намерение состояло в том, чтобы создать приложение с помощью JavaScript.
Я также стремился убедиться, что приложение отвечает всем требованиям, необходимым для квалификации в качестве прогрессивного веб-приложения или PWA, как они более известны.
На случай, если вы не знаете, что такое прогрессивное веб-приложение, вот «шаг лифта». Концептуально просто представьте себе стандартное веб-приложение, отвечающее определенным критериям. Соблюдение этого набора конкретных требований означает, что поддерживающее устройство (например, мобильный телефон) предоставляет веб-приложению особые привилегии, делая веб-приложение больше, чем сумма его частей.
В частности, на Android почти невозможно отличить PWA, созданное только с помощью HTML, CSS и JavaScript, от приложения, созданного с использованием собственного кода.
Вот контрольный список требований Google для приложения, которое считается прогрессивным веб-приложением:
- Сайт обслуживается по протоколу HTTPS;
- Страницы отображаются на планшетах и мобильных устройствах;
- Все URL-адреса приложений загружаются в автономном режиме;
- Метаданные для экрана «Добавить на главный экран»;
- Первая загрузка быстрая даже в 3G;
- Сайт работает кроссбраузерно;
- Переходы между страницами не блокируются в сети;
- У каждой страницы есть URL.
Теперь, кроме того, если вы действительно хотите быть любимцем учителя и ваше приложение считается «Образцовым прогрессивным веб-приложением», оно также должно соответствовать следующим требованиям:
- Содержимое сайта индексируется Google;
- Метаданные Schema.org предоставляются там, где это необходимо;
- Социальные метаданные предоставляются там, где это уместно;
- Канонические URL-адреса предоставляются при необходимости;
- Страницы используют History API;
- Контент не прыгает при загрузке страницы;
- При нажатии назад со страницы сведений сохраняется положение прокрутки на предыдущей странице списка;
- При касании ввод не закрывается экранной клавиатурой;
- Контентом легко поделиться из автономного или полноэкранного режима;
- Сайт адаптируется к экранам телефонов, планшетов и компьютеров;
- Любые подсказки об установке приложений не используются чрезмерно;
- Подсказка «Добавить на главный экран» перехватывается;
- Первая загрузка очень быстрая даже в 3G;
- Сайт использует сеть с приоритетом кеша;
- Сайт соответствующим образом информирует пользователя, когда он не в сети;
- Предоставьте пользователю контекст о том, как будут использоваться уведомления;
- Пользовательский интерфейс, побуждающий пользователей включать push-уведомления, не должен быть слишком агрессивным;
- Сайт затемняет экран, когда отображается запрос на разрешение;
- Push-уведомления должны быть своевременными, точными и актуальными;
- Предоставляет элементы управления для включения и отключения уведомлений;
- Пользователь входит в систему на разных устройствах через Credential Management API;
- Пользователь может легко оплатить через собственный пользовательский интерфейс из API запроса платежа.
Крики! Не знаю, как вам, но эта вторая куча вещей кажется огромной работой для базового приложения! Так уж получилось, что там есть много вещей, которые в любом случае не имеют отношения к тому, что я планировал. Несмотря на это, мне не стыдно признаться, что я понизил планку, чтобы пройти только начальные тесты.
Для целого раздела типов приложений я считаю, что PWA является более подходящим решением, чем собственное приложение. В то время как игры и SaaS, возможно, имеют больше смысла в магазине приложений, небольшие утилиты могут вполне счастливо и более успешно существовать в Интернете как прогрессивные веб-приложения.
Что касается того, что я уклоняюсь от тяжелой работы, еще один выбор, сделанный на раннем этапе, заключался в том, чтобы попытаться сохранить все данные для приложения на собственном устройстве пользователя. Таким образом, не нужно было бы подключаться к службам данных и серверам и иметь дело с входами в систему и аутентификацией. На том уровне, на котором были мои навыки, казалось, что определение аутентификации и хранение пользовательских данных почти наверняка потребует от меня больше, чем я мог проглотить, и переборщить с задачей приложения!
Выбор технологий
Имея достаточно четкое представление о цели, внимание было обращено на инструменты, которые можно использовать для ее достижения.
С самого начала я решил использовать TypeScript, который описан на его веб-сайте как «… типизированный расширенный набор JavaScript, который компилируется в простой JavaScript». То, что я видел и читал о языке, мне понравилось, особенно тот факт, что он так хорошо научился статическому анализу.
Статический анализ просто означает, что программа может просмотреть ваш код перед его запуском (например, когда он статичен) и выявить проблемы. Он не обязательно указывает на логические проблемы, но может указать на несоответствие кода набору правил.
Все, что могло указать на мои (конечно, многие) ошибки, должно было быть хорошим, не так ли?
Если вы не знакомы с TypeScript, рассмотрите следующий код в ванильном JavaScript:
console.log(`${count} players`); let count = 0;
Запустите этот код, и вы получите что-то вроде ошибки:
ReferenceError: Cannot access uninitialized variable.
Для тех, у кого есть хотя бы небольшой опыт в JavaScript, для этого базового примера им не нужен инструмент, чтобы сказать им, что все плохо кончится.
Однако, если вы пишете тот же код на TypeScript, это происходит в редакторе:
Я получаю отзывы о своем идиотизме еще до того, как запускаю код! В этом прелесть статического анализа. Эта обратная связь часто была похожа на то, что более опытный разработчик сидел рядом со мной и вылавливал ошибки, когда я работал.
Прежде всего TypeScript, как следует из названия, позволяет вам указать «тип», ожидаемый для каждой вещи в коде. Это предотвращает непреднамеренное «принуждение» одного типа к другому. Или попытка запустить метод для фрагмента данных, который неприменим — например, метод массива для объекта. Это не то, что обязательно приводит к ошибке при выполнении кода, но, безусловно, может привести к трудным для отслеживания ошибкам. Благодаря TypeScript вы получаете обратную связь в редакторе еще до того, как попытаетесь запустить код.
TypeScript, конечно, не был необходим в этом путешествии открытий, и я никогда не призывал бы никого прыгать на инструменты такого рода, если бы не было явной выгоды. Настройка инструментов и настройка инструментов в первую очередь могут занять много времени, поэтому обязательно подумайте об их применимости, прежде чем погрузиться в них.
Есть и другие преимущества, предоставляемые TypeScript, о которых мы поговорим в следующей статье этой серии, но возможностей статического анализа было достаточно, чтобы я захотел использовать TypeScript.
Были ложные соображения по поводу выбора, который я делал. Решение построить приложение как прогрессивное веб-приложение означало, что мне нужно будет в некоторой степени понимать Service Workers. Использование TypeScript означало бы введение каких-то инструментов сборки. Как мне управлять этими инструментами? Исторически я использовал NPM в качестве менеджера пакетов, но как насчет Yarn? Стоило ли вместо этого использовать Yarn? Ориентация на производительность означает рассмотрение некоторых инструментов минимизации или объединения; такие инструменты, как webpack, становились все более и более популярными и нуждались в оценке.
Резюме
Я осознал необходимость начать этот поиск. Мои способности к JavaScript были слабыми, и ничто так не подстегивает чресла, как попытки применить теорию на практике. Решение создать веб-приложение с ванильным JavaScript должно было стать моим боевым крещением.
Я потратил некоторое время на изучение и рассмотрение вариантов создания приложения и решил, что создание приложения в виде прогрессивного веб-приложения наиболее целесообразно для моего набора навыков и относительной простоты идеи.
Мне потребуются инструменты сборки, менеджер пакетов и, впоследствии, много терпения.
В конце концов, на этом этапе оставался фундаментальный вопрос: действительно ли я мог этим управлять? Или я буду унижен собственной несостоятельностью?
Я надеюсь, что вы присоединитесь ко мне во второй части, когда вы сможете прочитать об инструментах сборки, шаблонах проектирования JavaScript и о том, как сделать что-то более похожее на приложение.