PurePWA на мобильном устройстве

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

Было время, когда каждый браузер по-своему интерпретировал практически все. К счастью, эта эпоха давно позади.

Некоторые фреймворки и библиотеки фактически привели к эволюции самих веб-стандартов, например jQuery и React.

Теперь пришло время поразмыслить и внимательно посмотреть на наши практики разработки.

Все больше абстракций, усложняющиеся стратегии сборки и пакетирования, все больший размер в мегабайтах NPM-пакетов, предназначенных для чего угодно.

Разбиение на пакеты, “тряска” деревьев, ленивая загрузка частей пакета, виртуальная модель DOM, синтетические события  —  список можно продолжать.

Неужели мы сошли с ума?

Актуальные веб-стандарты? Кажется, мы потеряли с ними связь.

Недавно опрос State of HTML показал, что многие так называемые старшие разработчики не дотягивают даже до уровня младших специалистов (юниоров), когда дело доходит до базового понимания веб-стандартов.

По результатам опроса я попал в топ-1% с результатом 107/131, а один мой знакомый сообщил, что попал в топ-25% с результатом всего 80/131.

Вот об этом я и твержу все время: каждый из таких “старших” разработчиков полагается на свой фреймворк (или пакет, специально предназначенный для конкретного фреймворка), чтобы добиться результата, и даже не утруждает себя поиском прямого/нативного пути.

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

Пора изменить подход

Вот какой эксперимент я провел. Я создал очень простой, улучшенный веб-компонентами, не требующий сборки и зависимостей шаблон для PWA (прогрессивного веб-приложения), используя только средства современной веб-среды.

Вот ссылка на этот проект:

GitHub

Искусство дзен-медитации

Работа над проектом всегда похожа на дзен-медитацию: она отрезвляет, очищает, убирает все лишнее и просветляет.

Это действительно отличная идея  —  не начинать с фреймворка или любой другой большой зависимости. Вы ставите себе планы по достижению того-то и того-то и думаете, как заставить все это работать вместо того, чтобы обеспечить продукт всем необходимым. Не советую поступать так.

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

Я обнаружил, что современная веб-среда  —  прекрасное место. Выбирайтесь из своих кроличьих нор, созданных фреймворками, и отправляйтесь в исследовательское путешествие!

Вот что конкретно я имею в виду.

  • Начните со структуры HTML. Постарайтесь сделать так, чтобы она отображала то, что вам нужно. Не пытайтесь приукрасить ее, лучше сосредоточьтесь на смысле:
<label>
<span data-label>Animation</span>
<input type="range" min="0" max="1" step="1" name="animation" />
</label>

Обратите внимание: я заключил входные данные в <label>. Это позволяет избежать как атрибута ‘id’ во вводе, так и атрибута ‘for’ в метке. К тому же такая структура в полной мере поддерживается всеми браузерами.

  • Вы видите, что семантически элемент управления выражает переключение между двумя значениями: “0” и “1”.
  • Только когда вы будете довольны базовой структурой, попробуйте заставить ее работать без скриптов. В данном случае submit уже отправит сюда значение “1” или “0”.
  • Теперь, если нужно, дополните структуру с помощью скриптов, но делайте это, используя семантически подходящий пользовательский тег, а код расширения напишите в прилагаемом веб-компоненте.

Пример: элемент range с двоичными значениями, действующий как “переключатель”.

<range-switch>
<label data-form-element="switch" data-selected="@useAnimations">
<span data-label>Animation</span>
<input type="range" min="0" max="1" name="animation" />
</label>
</range-switch>

Скрипт:

import { CustomElement, enQueue} from "../../common.js";

customElements.define(
"range-switch",
/**
* Превращает вход [type="range"] в функцию Switch Control
*/
class RangeSwitch extends CustomElement {
static get observedAttributes() {
return ["value"];
}

attributeChangedCallback(name, oldValue, newValue) {
if (name === "value" && newValue) {
this.querySelector("input").value = parseInt("0" + newValue);
}
}

connectedCallback() {
const condition = () => {
return range.value === "1";
};

const range = this.querySelector('input[type="range"]');

range.addEventListener("input", (e) => {
this.setAttribute("value", condition() ? 1 : 0);
});

enQueue(() => {
this.setAttribute("value", condition() ? 1 : 0);
});
}
}
);

Класс CustomElement подробно рассмотрен в readme репозитория GitHub.

Теперь упорядочьте код:

range-switch {
input[type="range"] {
appearance: none;
width: 3rem;
height: 1.2rem;
background: var(--color-surface-mixed-100);
outline: none;
border-radius: 50px;
cursor: pointer;
transition: .2s ease-in-out;
padding: 0;

&:focus {
outline: 2px solid var(--color-accent);
}

&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 1.4rem;
height: 1.4rem;
background: var(--color-accent);
filter: saturate(0);
border-radius: 50%;
cursor: pointer;
transition: .2s ease-in-out;
}
}

&[value="1"] {
input[type="range"] {
&::-webkit-slider-thumb {
filter: none
}
}
}
}

Принципы PurePWA

Помните: это радикальный эксперимент. Я не призываю использовать только те принципы, которых придерживаюсь. Я сам применяю их лишь для того, чтобы доказать одну вещь: вам нужны только чистые веб-стандарты, чтобы разрабатывать отличные/прогрессивные веб-приложения.

Говорим “да”:

  • семантическому HTML;
  • полноценному прогрессивному веб-приложению;
  • веб-компонентам;
  • прогрессивному расширению;
  • стопроцентным результатам по всем категориям Lighthouse;
  • импорту ES-модулей во время выполнения;
  • иконкам в формате SVG-спрайтов;
  • “нативному” внешнему виду и пользовательскому опыту.

Говорим “нет”:

  • NPM;
  • системе сборки;
  • полифиллам¹;
  • пакетированию;
  • TypeScript (используем только 100 % ванильный JavaScript);
  • зависимостям.

Что в результате?

Приложения, созданные с помощью этого подхода, не страдают от недостатка сложности.

Фактически, конечные пользователи не заметят разницы.

Что они могут заметить, так это огромную скорость и легкость начальной загрузки.

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

PurePWA на настольных ПК и мобильных устройствах

Начинайте работу, думая о конечном пользователе

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

Как я уже говорил, сообщество веб-разработчиков слишком много внимания уделяет опыту разработчиков и слишком мало  —  конечным пользователям.

Мы все забываем, что у конечных пользователей нет ни таких высококлассных устройств, как у нас, ни такой пропускной способности интернета, к которой мы так привыкли. Поэтому, когда мы устанавливаем себе свои приложения и переходим с одного раздела на другой, нам кажется, что все в порядке. В то же время владельцу старого телефона на базе Android с плохим сигналом Wi-Fi или, что еще хуже, 3G/4G приходится ждать несколько секунд, чтобы хоть что-то увидеть, и еще больше, чтобы перейти к функциям полноценной интерактивности.

Показатели Lighthouse для PurePWA

Следующие шаги

Этот эксперимент очень интересен. Но он еще не окончен.

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

Сноска:

¹ Добавлены полифиллы для навигации: события navigate и метода Document: startViewTransition().

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Marc van Neerven: PurePWA — A Radical U-Turn in Web Development

Предыдущая статья4 причины использовать перечисления PHP вместо старомодных констант класса
Следующая статьяSpring Boot, Kafka и WebSocket для отправки сообщений в реальном времени