🔥

Тред (Сергей Куликов)


Тред про кастомные элементы без зависимостей, с примерами из личного опыта. И заодно немного о best practices.

Кастомные элементы без зависимостей писали еще 5 лет назад, на “версии 0”. Вот, например, популярный в то время компонент роутера (и один из первых проектов на GitHub, куда я контрибьютил). github.com/erikringsmuth/…

Правда, долгое время была одна неявная зависимость: полифилл. Его нужно было подключать на страницу отдельным скриптом, размер которого в среднем составлял 5-6 KB (min + gzip). npmjs.com/package/@webco…

Кроме “официального” полифилла от разработчиков Google, был еще document-register-element от Andrea Giammarchi. Он использовался в Angular и AMP. На данный момент deprecated и уже архивирован. github.com/WebReflection/…

Еще один момент: кастомные элементы требуют нативных ES2015-классов. Это тоже своего рода зависимость. ES5-код, полученный с помощью Babel, не будет работать с customElements.define.

Решается эта проблема с помощью с помощью манки-патчинга HTMLElement с добавлением вызова Reflect.construct. В составе “официального” полифилла для этого есть отдельный скрипт. github.com/webcomponents/…

По вышеуказанной причине в сообществе веб-компонентов принято публиковать в npm исходный код кастомных элементов в ES2015. Примеры, которые будут в этом треде, следуют этому правилу.

@mlfrg У библиотеки одна зависимость — React :)
Итак, рассказываю о двух своих недавних пет-проектах. Это “клоны” React-компонентов, написанные на ванильных кастомных элементах без зависимостей. Вся эта история началась с твита: twitter.com/pepelsbey/stat…

Так появился проект vanilla-colorful, порт колор-пикера react-colorful от @Omgovich (если пропустили его неделю, обязательно почитайте). github.com/web-padawan/va…

@pepelsbey @mlfrg Переписал на Custom Elements. Вот теперь действительно ноль зависимостей 🙂 github.com/web-padawan/va…
От идеи до реализации прошло всего несколько дней. Замечу, что опыта разработки на React у меня нет. Исходный код react-colorful хорошо оформлен и снабжен комментариями, это очень помогло. twitter.com/iamkulykov/sta…

Подробнее можно узнать в 248 выпуске подкаста Веб-стандарты, где мы с @Omgovich обсуждали наши колор-пикеры и сравнивали плюсы и минусы используемых подходов. medium.com/web-standards/…

Второй мой проект — vanilla-hamburger: набор гамбургер-кнопок с разными анимациями, порт библиотеки hamburger-react. В отличие от оригинала, под капотом использует <button>, а не <div>. github.com/web-padawan/va…

Оба проекта написаны на TypeScript и покрыты тестами. Об этом, пожалуй, сделаю чуть позже отдельный тред. А пока несколько слов о подходах, использованных при написании этих компонентов.

Как и стандартные HTML элементы, кастомный элемент может иметь атрибуты и свойства. По умолчанию они не связаны между собой. В качестве решения обычно используется пара геттер-сеттер. gist.github.com/web-padawan/3d…
notion image

В этом примере я использую Symbol, чтобы эмулировать приватное поле. Это полезно, поскольку иначе в автокомплите и браузерных DevTools будет много лишнего. Подробнее в статье Jan Miksovsky: component.kitchen/blog/posts/hid…

В сеттерах свойств принято вызывать сайд-эффекты (например, обновлять DOM). Значения по умолчанию задаются в constructor, это позволяет переопределять их с помощью атрибутов. gist.github.com/web-padawan/3d…
notion image

Свойство может быть установлено до того, как элемент связан с классом. При этом геттер и сеттер будут "затенены" (shadowed). Чтобы это исправить, вызываем сеттер в connectedCallback. gist.github.com/web-padawan/08…
notion image

С помощью пары строк кода реализуем простейший асинхронный рендеринг. Этот подход (batch updates) позволяет обновлять DOM один раз за микротаск при изменении нескольких свойств. gist.github.com/web-padawan/79…
notion image

Какой-то Angular первых версий twitter.com/jsunderhood/st…
Насчет сравнения с “Angular первых версий” — на самом деле, намного больше все это похоже на lit-element. Если точнее, его базовый класс UpdatingElement, который не требует lit-html. twitter.com/anber_ru/statu…

Еще один интересный прием — встроенный метод handleEvent для обработчиков событий. Он позволяет обойтись без использования .bind(this) или стрелочных функций в addEventListener. gist.github.com/web-padawan/36…
notion image

Некоторые из описанных приемов можно увидеть в проекте HowTo: Components от авторов Web Fundamentals. Он не обновлялся три года, но до сих пор актуален — одно из преимуществ стандартов. github.com/GoogleChromeLa…

Также на Web Fundamentals есть список best practices для кастомных элементов. Там достаточно подробно описаны атрибуты и свойства (и как при работе с ними избежать бесконечного цикла). developers.google.com/web/fundamenta…

В качестве более обзорного чтения советую Gold Standard Checklist от Jan Miksovky, на чьи работы я часто ссылаюсь. Он содержит ряд требований к API веб-компонентов, доступности и многое другое. github.com/webcomponents/…

И в завершение треда — еще один чеклист от Justin Fagnani о том, как публиковать кастомные элементы в npm. Есть полезные советы о структуре пакетов, важные поля package.json и так далее. justinfagnani.com/2019/11/01/how…