Сергей Куликов

Сергей Куликов

Темы
Неделя
Nov 9, 2020 → Nov 15, 2020

Архив недели @iamkulykov

Понедельник


Всем привет! С вами Сергей Куликов (@iamkulykov). Работаю в Vaadin, последние 4 года пишу на веб-компонентах.

Темы недели: — Кастомные элементы: все еще не торт? — Shadow DOM как средство изоляции — Ванильные компоненты без зависимостей — Разработка на ES-модулях в браузере — Библиотеки компонентов и open source

В Vaadin занимаюсь разработкой и поддержкой нашей библиотеки компонентов на Polymer 2 и 3 (в будущем планируем перейти на lit-element). Разработка ведется в open source: github.com/vaadin/vaadin

До Vaadin работал в компании OWOX, где участвовал в поэтапной миграции приложения с Polymer 0.5 на 1.0. Застал все версии Polymer и могу многое о нем рассказать (в том числе и о недостатках).

🔥Тред (Сергей Куликов)
Тема первого дня — кастомные элементы. Как в узком смысле (часть стандарта HTML), так и в широком (framework-agnostic подход к написанию компонентов и приложений на их основе).

Опрос: знакомы ли вы с кастомными элементами?
🤔 21.6% Впервые слышу
🤔 55.5% Знаю в общих чертах
🤔 11.8% Есть некоторый опыт
🤔 11.0% Использую в работе

Если слышите впервые, советую эту главу в учебнике Ильи Кантора. Она небольшая, но хорошо описывает API и некоторые тонкости. learn.javascript.ru/custom-elements

Поддержка браузерами — кроме IE11 и старого Edge. Многих наверняка смутит “partial support” в Safari, сейчас объясню. caniuse.com/custom-element…

Дело в том, что разработчики WebKit принципиально отказались внедрять модифицированные встроенные элементы (customized builtin elements). С их позицией можно ознакомиться здесь. github.com/WICG/webcompon…

Использовать браузерные API, относительно которых не достигнут консенсус, я не советую. Так что дальше речь пойдет об автономных кастомных элементах, реализованных в Chrome, Safari и Firefox.

Автономные кастомные элементы сами по себе умеют немногое. По сути это те же span, у которых есть жизненный цикл и которым не нужен Mutation Observer, чтобы отслеживать изменения атрибутов.

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

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

Часть этих улучшений и базовое для них API Element internals уже добавлены в стандарт WHATWG. Но в стабильных версиях браузеров этих дополнений пока нет (кое-что есть только в Chrome).

Кстати, вы любите читать спецификации? Я обычно первым делом ищу в них разделы, отмеченные как “non-normative”. Там можно почерпнуть ценную информацию, не углубляясь в детали.

В не нормативных разделах спецификации кастомных элементов можно найти ответы на вопросы “зачем”, “как” и “чего пока не хватает”. Отдельно советую пример элемента taco-button. html.spec.whatwg.org/multipage/cust…

Самый простой способ потестить кастомные элементы — сайт webcomponents.dev. Есть примеры разных библиотек и vanilla JS.

🔥Тред (Сергей Куликов)
Возможны, вы заметили, что до сих пор я избегал термина “веб-компоненты”. Думаю, тред на эту тему будет не лишним.

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

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

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

Одна из причин негатива — вместе с полезными API, ставившими задачу объяснить устройство HTML, активно навязывались попытки радикально его переосмыслить. Прежде всего, HTML Imports.

HTML Imports вместе со спорными аспектами Shadow DOM оказались камнями преткновения, по вине которых веб-компоненты, доступные за флагом в Firefox, дождались релиза лишь спустя годы. hacks.mozilla.org/2014/12/mozill…

Недостаткам ранней реализации, существовавшей только в Chrome и впоследствии печально известной как “версия 0”, посвящен доклад TJ VanToll “Web Components — What’s the Catch?” tjvantoll.com/speaking/slide…

Веб-компоненты "версии 0" были сложными, далекими от реальных проблем (таких, как стилизация select) и во всех браузерах кроме Chrome требовали полифиллов, убивавших производительность.

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

В разное время над DevRel в области веб-компонентов работали Addy Osmani, Eric Bidelman, Rob Dodson, Monica Dinculescu, Mark Dalgleish. Некоторые из них позже дистанцировались от этой темы.

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

Jan Miksovsky, один из участников тех событий, написал статью с детальной хронологией и рассказал о том, как были разрешены ключевые противоречия в области Shadow DOM. component.kitchen/blog/posts/a-h…

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

В итоге до сих пор бытует мнение, что Custom Elements и Shadow DOM — детище Google, которое кроме продуктов этой компании (YouTube, интерфейс Chrome) якобы нигде не используется.

I specialized in some losers: Cold Fusion, Flash, web components. But I also got lucky and went big on React early. That single good bet has had ongoing, big returns.
Некоторые вообще называют веб-компоненты мертворожденной технологией. Но особенно я был удивлен, увидев их упоминание в одном ряду с Flash (автор цитируемого твита — сторонник React). twitter.com/housecor/statu…

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

Но личным опытом разработки на bleeding edge я поделюсь позже. Если, конечно, веселые истории из серии “мыши плакали, кололись” и постмортем пожирания кактуса кому-то интересны.

🔥Тред (Сергей Куликов)
Тред о применении кастомных элементов в 2020. С момента релиза Firefox 63 прошло почти два года, в Safari поддержка появилась еще раньше. Так что уже можно делать некоторые выводы.

На сегодняшний день кастомные элементы используют Adobe, Apple, Esri, GitHub, Firefox, IBM, ING, Internet Archive, Microsoft, Nintendo, Oracle, Red Hat, Salesforce, SAP, Tencent, Tesla, VMWare.

По данным Chrome Platform Status, уровень использования достигает 10% показов страниц. Их методика подсчета и провалы на графике вызывают вопросы, но другой такой статистики я не встречал. chromestatus.com/metrics/featur…

Причина роста популярности — у ряда крупных компаний есть запрос на framework-agnostic. Типичный юзкейс: библиотека компонентов, используемая в проектах на разных фреймворках.

На самом деле, от фреймворков поддержка кастомных элементов требует определенных усилий. Набор тестов на совместимость можно найти на сайте Custom Elements Everywhere. custom-elements-everywhere.com

Обращаю внимание на то, что с React все не так просто. Есть надежда, что полная совместимость появится в React 18. github.com/facebook/react…

Возможно, поэтому некоторые компании поддерживают две реализации своей дизайн-системы — на React и на кастомных элементах: Spectrum от Adobe, Carbon от IBM, PatternFly от RedHat.

Для разработки в энтерпрайзе кастомные элементы привлекательны возможностью постепенно модернизировать существующий стек технологий, избегая внешних зависимостей и vendor lock-in.

При этом стек может быть любым: свой фреймворк (LWC от Salesforce, UI5 от SAP, FAST от Microsoft), набор библиотек вроде jQuery и Knockout (Oracle JET), библиотека компонентов (Sencha ExtWebComponents).

В Vaadin мы используем кастомные элементы как фундамент для Java-фреймворка, предыдущая версия которого была основана на GWT. Публичные API во многом удалось сохранить.

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

Интересный сценарий — инкрементальная миграция с помощью кастомных элементов. Этот подход описал Денис Мишунов в докладе "Я создал Франкенштейна" и статье в двух частях. smashingmagazine.com/2019/09/franke…

Особенность “франкенштейн-миграции” в том, что кастомные элементы и Shadow DOM в данном случае — средство, а не цель. Если для проекта такой вариант оптимален, почему бы и нет?

К похожим юзкейсам я бы отнес микрофронтенды. Кастомные элементы упоминаются как один из элементов концепции, которую сформулировал Michael Geers на сайте micro-frontends.org

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

Встраиваемые виджеты могли бы не засорять страницу своей разметкой, пряча ее за HTML-тегом. Также им пригодилась бы изоляция Shadow DOM, о котором мы еще поговорим.

Но вообще использовать Shadow DOM вместе с кастомными элементами не обязательно. Это независимые части стандарта, напрямую никак не связанные между собой.

Разработчики GitHub следуют идее прогрессивного улучшения и используют кастомные элементы без Shadow DOM. Об этом они рассказали в известной статье о выпиливании jQuery. github.blog/2018-09-06-rem…

Кастомные элементы GitHub (в частности, меню и модальный диалог) сохраняют часть функций при выключенном JavaScript благодаря использованию стандартного элемента <details>. github.com/github/details…

Но этот пример — исключение. Чаще кастомные элементы используют там, где о выключенном JS не заботятся. Это админки, дашборды, корпоративные порталы с формочками и табличками.

Среди примеров могу назвать инструменты для CMS от проекта HAX (редакторы для Drupal и Wordpress) и Joomla UI custom elements (частично на них построен интерфейс админки Joomla 4).

В концепцию генераторов статики кастомные элементы тоже вписываются (они же сами — часть HTML). Чаще других в этом смысле упоминают 11ty. Вот, например, статья от авторов web.dev. web.dev/how-we-build-w…

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

Плагины вроде Swiper обычно требуют HTML с определенными классами или атрибутами. Кастомный элемент с Shadow DOM мог бы помочь сделать код чище, а API — более унифицированным.

Напоследок упомяну еще и про такой феномен, как “HTML framework” (термин предложил Paul Bakaus из команды AMP). Пример подобного набора примитивов — Numl от @tenphi. github.com/numldesign/numl

🔥Тред (Сергей Куликов)
На этом на сегодня все. Завтра будет больше практических моментов из личного опыта. Еще поговорим о пока не решённых проблемах. И, конечно же, обсудим некоторые из ваших пожеланий.

Вторник


Первый тред на сегодня — о том, нужны ли кастомным элементам библиотеки и в каких случаях можно обойтись vanilla JS.

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

В итоге возникает ассоциация "кастомные элементы = библиотека” и закономерный вопрос: так ли полезен стандарт, если без библиотек все равно никуда? Об этом однажды написал Chris Coyier. css-tricks.com/a-bit-on-web-c…

В комментариях к статье Rob Dodson заметил, что веб-компоненты — набор низкоуровневых примитивов. Библиотеки и фреймворки могли бы использовать их, чтобы изобретать меньше абстракций.

@Rich_Harris @edsilv @FabianCook @justinfagnani However we simply don't see enough value to adopt WC as the foundation to build the application component model upon. In fact it leads to more problems than gains.
Так это выглядело на бумаге. Но на сегодняшний день реальность такова, что авторы фреймворков не видят смысла использовать API кастомных элементов. Например, об этом говорил Evan You: twitter.com/youyuxi/status…

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

Веб-компоненты эту задачу не решают от слова совсем. Они ничего не говорят нам о том, как и когда рендерить — они предлагают, что именно рендерить (кастомные HTML-элементы).

Об этом, в частности, говорит один из разделов документации React. Изложенная там позиция лишена критики в адрес веб-компонентов, но общий посыл очевиден: “скорее всего, вам это не нужно”. reactjs.org/docs/web-compo…

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

Отсюда и вбросы вроде “web components will replace your framework”. По-моему, от таких заголовков больше вреда, чем пользы. Увы, некоторые из сторонников веб-компонентов этим страдают.

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

Но значит ли это, что библиотека / фреймворк нужны всегда? Я так не думаю. Бывают случаи, где тащить лишние килобайты JS вовсе не обязательно и вполне хватает нативных API на чистом JS.

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

Когда-то у Polymer был слоган “jQuery для веб-компонентов” — то есть, набор костылей, потребность в которых со временем отпадет. Но годы идут, и что-то пока библиотек становится только больше.

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

Я бы выделил три основных типа библиотек: — основанные на классах (lit-element, FAST), — основанные на функциях (Haunted, Atomico), — компиляторы (Stencil, LWC, Solid).

В этой статье перечислены более 40 способов написать один и тот же простой веб-компонент, с бенчмарками и сравнением размеров бандла. В том числе, представлены и фреймворки. webcomponents.dev/blog/all-the-w…

Статья демонстрирует, что при использовании ванильных кастомных элементов размер бандла быстро разрастается, когда компонентов в приложении становится больше (в приведенном примере их 30).

Мне этот факт напоминает расхожую фразу: начнешь писать на чистом JS — рано или поздно напишешь свой фреймворк. Что не обязательно плохо, ведь в процессе можно многому научиться.

Если вы пишете на библиотеке — стоит понимать, как она работает. В этом помогает чтение исходников и особенно тестов. В свое время я изучал таким образом устройство Polymer и lit-element.

О своем опыте применения этих знаний в написании кастомных элементов без зависимостей расскажу в следующем треде.

🔥Тред (Сергей Куликов)
Тред про кастомные элементы без зависимостей, с примерами из личного опыта. И заодно немного о 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…

🔥Тред (Сергей Куликов)
Тред о кастомных элементах на TypeScript и тестировании.

Для начала о TypeScript. Прежде всего, кастомный элемент стоит добавить в интерфейс HTMLElementTagNameMap. Это сделает его тип доступным в методах querySelector и document.createElement. gist.github.com/web-padawan/c8…
notion image

Если вы используете React, нужно также добавить определение кастомного элемента в специальный интерфейс JSX.IntrinsicElements. Это позволяет описать поддерживаемые свойства и их типы. gist.github.com/web-padawan/52…
notion image

Еще можно типизировать кастомные события, которые используются элементом, для вывода типа event.detail в addEventListener. На днях James Garbutt опубликовал статью о том, как это сделать. 43081j.com/2020/11/typed-…

Поскольку кастомные элементы используют нативные классы, общая логика в них обычно выделяется в миксины. По сути миксин — это функция, принимающая класс и возвращающая новый класс. gist.github.com/web-padawan/a0…
notion image

Подробнее о том, как работают миксины в TypeScript, можно почитать в статье Николая Платонова. Кроме преимуществ, у этого паттерна есть недостатки и некоторые ограничения. bryntum.com/blog/the-mixin…

Перейдем к тестированию. Кастомные элементы можно тестировать с помощью Jest с тех пор, как была добавлена их поддержка в jsdom 16.2 благодаря усилиям Pierre-Marie Dartus из Salesforce.

Пример конфига Jest с использованием TypeScript для тестирования проекта на lit-element можно найти в темплейте Hoverboard от GDG. github.com/gdg-x/hoverboa…

В Vaadin мы тестируем наши веб-компоненты в реальных браузерах. Это помогает обнаружить баги, которые воспроизводятся, например, только на iOS или появляются в свежей версии Chrome / Firefox.

Раньше в экосистеме Polymer был свой тест-раннер: web-component-tester. Необходимость в нем была обусловлена использованием HTML Imports, позже появилась и поддержка ES-модулей.

Сейчас мы переходим на Web Test Runner, который разрабатывает Lars den Bakker из ING. Он быстрый, поддерживает ES-модули, позволяет запускать тесты в Puppeteer, Playwright и не только. modern-web.dev/docs/test-runn…

@jsunderhood А почему не получается использовать Mocha/Jest и другие классические инструменты?
Почему переходим не на Jest? Во-первых, нам часто приходится дебажить edge cases в конкретном браузере. Кроме того, насколько я понимаю, Jest из коробки не поддерживает ES-модули. twitter.com/justboriss/sta…

Также в Web Test Runner есть и экспериментальная поддержка тестирования скриншотами. До сих пор мы использовали Gemini, который уже не поддерживается и довольно медленный.

Для тестирования компонентов на TypeScript в Web Test Runner есть плагин на базе esbuild. Компиляция в esbuild занимает доли секунды и на длительность выполнения тестов почти не влияет. modern-web.dev/docs/dev-serve…

Пример конфигурации Web Test Runner и собственно тесты для кастомных элементов можно найти в моих проектах vanilla-colorful и vanilla-hamburger, о которых я рассказал в предыдущем треде.

🔥Тред (Сергей Куликов)
Я обещал рассказать о не решенных проблемах кастомных элементов. В этом треде перечислю основные из них.

В моем списке есть пробелы, требующие доработок и новых API в браузерах, но это еще полбеды. На мой взгляд, более существенные проблемы проистекают из самой природы кастомных элементов.

Проблема № 1: кастомные элементы не работают с выключенным JS. Это заметно ограничивает область их применения. Есть черновик декларативного синтаксиса, но пока в стадии наброска. github.com/WICG/webcompon…

Проблема № 2: кастомные элементы не имеют кросс-браузерной поддержки форм. Form associated custom elements API уже добавлено в стандарт, но реализовано только в Chrome… Here we go again. web.dev/more-capable-f…

Проблема № 3: кастомный элемент с одним и тем же тегом можно определить только один раз. Это значит, что на странице нельзя использовать две версии одного компонента (будет exception).

Это одна из причин, почему Polymer долго использовал Bower: там плоское дерево и установить две версии одного пакета невозможно. В npm нужно следить за версиями и надеяться на dedupe.

В Vaadin мы обходим эту проблему с помощью pnpm. Там есть возможность гибкой настройки с помощью pnpmfile.js. Версии можно модифицировать в процессе установки в хуке readPackage. pnpm.js.org/en/pnpmfile#ho…

Проблема № 4: поскольку переопределять кастомные элементы нельзя, hot module replacement не работает. Есть полифилл, который патчит customElements.define и методы жизненного цикла. github.com/vegarringdal/c…

Проблема № 5: кастомные элементы регистрируются глобально. В сочетании с невозможностью их переопределения это критично для больших проектов, разрабатываемых многими командами.

Решить эту проблему призван черновик Scoped Custom Element Registries, над которым работают представители Google и Salesforce. Сейчас идет обсуждение аспектов, связанных с Shadow DOM. github.com/WICG/webcompon…

Пробная реализация в виде миксина для lit-element есть в проекте Open Web Components. Имеется ряд ограничений, в частности требование не определять используемые элементы глобально. open-wc.org/docs/developme…

Иногда базовые классы специально отделяют от определений кастомных элементов и выносят в отдельные файлы без сайд-эффектов. Я следую этому принципу. Статья на эту тему: component.kitchen/blog/posts/sup…

@jsunderhood Я бы в список добавил еще хаотичный порядок connectedCallback, из-за которого нельзя делать нормальную композицию компонентов: twitter.com/justboriss/sta… Вкупе с elements upgrade это создает огромное поле для наступания на грабли.
Из комментариев: проблема № 6, связанная с жизненным циклом. Мне с ней сталкиваться не приходилось, но реализованное в браузерах поведение выглядит сложным и создает риски. twitter.com/justboriss/sta…

Проект HowTo: Components для решения проблем с порядком загрузки использует Promise внутри connectedCallback. Как я понимаю, это единственный надежный способ.
notion image

Напоследок упомяну некоторые черновики новых API, которые в перспективе могут облегчить жизнь разработчикам кастомных элементов. Прежде всего, это механизм обработки фокуса. github.com/WICG/webcompon…

Второй пример — кастомные псевдо-классы, доступные за флагом в Chrome 79+. Скорее всего они, как и кастомные CSS свойства, будут требовать префикс из двух дефисов, например my-element:--active github.com/WICG/webcompon…

Наконец, одно из недавних дополнений к стандарту — способность указывать ARIA-роли и поведение по умолчанию без использования атрибутов. Этот механизм появился в стабильном Chrome 81. chromestatus.com/feature/596210…

🔥Тред (Сергей Куликов)
На сегодня все. Завтра поговорим о Shadow DOM, о том, что значит его изоляция на практике и какие ограничения она накладывает.

Среда


Сегодняшняя тема — Shadow DOM, его возможности и ограничения. Начнем с треда о главной проблеме, которую Shadow DOM призван решить: глобальный неймспейс и отсутствие в CSS изоляции.

Этим летом я выступал на DevParty Russia с докладом “Shadow DOM: вдали от проторенных троп”. Тред отчасти написан по его мотивам. youtu.be/97_zqVXwAj4?t=…

“Проторенной тропой” я называю способы инкапсуляции стилей, ставшие традиционными: БЭМ и другие методологии, CSS modules, CSS-in-JS. Все это — варианты именования или генерации классов.

Сразу определимся с терминами: инкапсуляция = стили компонента не протекают наружу. Изоляция = то же самое плюс отсутствие для внешних, глобальных стилей возможности проникнуть внутрь.

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

В статье на Web Fundamentals есть фраза “Shadow DOM fixes CSS and DOM”. Я бы сказал, все обстоит наоборот: он ломает некоторые привычные представления, требуя иначе структурировать код. developers.google.com/web/fundamenta…

Пример: если на странице есть reset, normalize или глобальные стили для box-sizing, внутри shadow root они не применятся. Это, впрочем, не столь важно при использовании компонентного подхода.

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

Но повсеместное использование Shadow DOM чревато рядом последствий. Mattia Astorino приводит хорошую аналогию: завернуть приложение в shadow root — все равно что поместить его в <input>. equinusocio.dev/blog/web-compo…

Это ключевой момент: изоляция Shadow DOM подобна той, которой обладают встроенные HTML-элементы. О том, как это выглядит на практике, можно почитать в статье Ire Aderinokun. bitsofco.de/what-is-the-sh…

Кстати, заглянуть внутрь <input type=“range”> или <video> можно не только в браузерах на основе Chromium (галочка “show user agent shadow DOM” в настройках DevTools), но и в Safari.

Изоляция исключает конфликты из-за имен классов, селекторов по ID и тегам. Это полезно, но в реальных проектах регулярно возникает необходимость в сторонней библиотеке на CSS-классах.

Раньше в слаке Polymer регулярно звучал вопрос “как использовать Bootstrap внутри Shadow DOM” (стоп, а нужна ли тогда изоляция?). Сегодня тенденция поменялась: стали спрашивать про Tailwind.

Что примечательно, такие вопросы задают не только новички. То есть, причина не в отсутствии понимания принципов изоляции, а в желании сохранить удобные, устоявшиеся практики.

С одной стороны, Shadow DOM позволяет забыть об именовании классов. Но, устраняя одну из причин появления CSS-методологий, изоляция не отменяет необходимости писать поддерживаемый код.

В результате у Material Web Components мы можем внутри shadow DOM увидеть классы, именуемые по БЭМ (правда, это связано и с тем, что базовые стили подключаются из отдельного npm-пакета). github.com/material-compo…

Подытожим: изоляция Shadow DOM предлагает решение одной из важных проблем CSS, но при этом приносит новые. Иногда его использование оправдано, но в целом этот подход не взлетел.

Hey CSS friends, does this make sense to you? @ scope (.airplane) end (.passenger_cabin, .cockpit, .luggage_compartment) If you had to guess, what does this do?
Добавлю, что Nicole Sullivan из Google уже зондирует почву на предмет альтернативной инкапсуляции на CSS media queries. В поддержку высказался Rich Harris, известный критик Shadow DOM. twitter.com/stubbornella/s…

🔥Тред (Сергей Куликов)
@jsunderhood Я, кстати, недавно обратил внимание, что некоторые компании используют Shadow DOM для того, чтобы делать браузерные extension-ы, которые встраивают элементы на страницы. Мне кажется, что, для этой задачи, такой подход к изоляции стилей весьма удачен. pic.twitter.com/xxiBPgSLhq
Встраиваемые виджеты — действительно один из тех случаев, где изоляция оправдана. Кстати, не знал, что Grammarly использует Shadow DOM. Еще его одно время использовал Twitter. twitter.com/Omgovich/statu…

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

Размещать стили внутри Shadow DOM обычно рекомендуется с помощью элемента <style>. Для тех, кто придерживается строгих правил CSP, это означает необходимость unsafe-inline.

Современные браузеры кэшируют содержимое <style>, так что на производительность этот способ не влияет. Можно использовать и <link rel=“stylesheet”>, но так обычно не делают из-за FOUC. developer.mozilla.org/en-US/docs/Web…

Еще есть Constructable Stylesheets — эксперимент, реализованный только в Chrome и по их замерам более производительный. Это API используется в lit-element с фолбеком на <style> для Firefox и Safari. developers.google.com/web/updates/20…

По инициативе разработчиков WebKit идет обсуждение, каким образом устранить выявленные недостатки в этом API. В связи с наличием двух разных позиций дискуссия затянулась. github.com/WICG/construct…

Важен этот черновик тем, что является одной из ступенек на пути к Cascading Stylesheet Module Scripts. В перспективе это возможность нативно импортировать стили из CSS-файлов в JavaScript. github.com/WICG/webcompon…

Рабочее название этого API — “CSS modules”. Хотя против него были возражения в связи с тем, что существует популярная библиотека с таким названием и могла бы возникнуть путаница. github.com/WICG/webcompon…

Но черновики — вопрос будущего, а пока мы говорим об элементах <style>, добавление которых требует JS. Стоит ли полагаться на такой подход? Решайте сами, исходя из конкретных задач.

Пример реализации для React — библиотека Cease, всего 30 строк и 500 байт без зависимостей. Советую заглянуть в ее документацию, там хорошо описаны подводные камни Shadow DOM. github.com/steobrien/cease

Также рекомендую пример конфигурации webpack и style-loader для работы с Shadow DOM в проектах на React и Vue, приведенный во второй части статьи Дениса Мишунова о Frankenstein Migration. smashingmagazine.com/2019/09/franke…

🔥Тред (Сергей Куликов)
Еще один важный аспект Shadow DOM — кастомизация стилей. При наличии изоляции это становится проблемой, поскольку некоторые стили надо переопределять. Небольшой тред на эту тему.

Первое, о чем стоит помнить: наследуемые свойства (color, font-family и другие) на элементе с shadow root проникают внутрь, то есть каскад работает. Некоторые считают это поведение проблемой.

Кастомные свойства (CSS-переменные) являются наследуемыми по умолчанию и тоже пересекают границы Shadow DOM. Если объявить свойство на html, оно будет доступно в любом shadow root. developer.mozilla.org/en-US/docs/Web…

Кастомные свойства можно комбинировать с селектором :host() и устанавливать их значения в зависимости от атрибута на элементе. Это позволяет поддерживать разные темы или варианты. gist.github.com/web-padawan/4b…
notion image

О селекторах :host и :host() можно почитать на MDN и в учебнике Ильи Кантора. Замечу, что :host-context() есть только в Chrome и, вероятно, будет удален из-за проблем с производительностью. learn.javascript.ru/shadow-dom-sty…

Долгое время кастомные свойства были единственным способом кастомизации в библиотеках веб-компонентов. Это было не так уж удобно: не делать же переменную для каждого CSS-свойства.

Polymer и компоненты Paper Elements использовали механизм CSS-миксинов. Они так и не стали стандартом и не были реализованы в браузерах. Tab Atkins в своем блоге объяснил, почему. xanthir.com/b4o00

При использовании кастомных элементов можно модифицировать стили с помощью наследования: класс-потомок переопределяет CSS родителя. Этот подход использовался в библиотеке Elix. component.kitchen/blog/posts/our…

Не так давно (Firefox 72, Safari 13.1) появились CSS Shadow Parts. На сегодняшний день это рекомендуемый способ кастомизации Shadow DOM. О том, как он работает, у меня есть статья с примерами. dev.to/webpadawan/css…

Вкратце, псевдоэлемент ::part() позволяет переопределять стили отдельных элементов в Shadow DOM, имеющих атрибут part — подобно тому, как это делает ::placeholder() для нативного input. developer.mozilla.org/en-US/docs/Web…

Изначально вместе с ::part() предлагался также селектор ::theme() для решения проблемы темизации компонентов. На данный момент он не реализован, идет обсуждение возможных альтернатив. github.com/WICG/webcompon…

Единственным механизмом темизации пока остаются кастомные CSS свойства. Cassondra Roberts из Red Hat предложила подход к их именованию, применяемый в библиотеке PatternFly Elements. github.com/castastrophe/w…

🔥Тред (Сергей Куликов)
@jsunderhood Вот здесь интересная штука получается. Vaadin предоставляет компоненты для Enterprise-компаний, который обычно пекутся о своей безопасности и любят закручивать гайки в CSP. Как при этом получается использовать ShadowDOM в компонентах?
Вопрос о Shadow DOM и CSP в Vaadin: на самом деле клиент Java-фреймворка до сих пор использует GWT и поэтому там нужен и unsafe-eval. Но при этом бизнес-логика выполняется на сервере. twitter.com/justboriss/sta…

Тред про ограничения Shadow DOM и связанные с ними проблемы.

Как и кастомные элементы, Shadow DOM имеет ряд ограничений, наиболее важные из которых обусловлены самим устройством API, реализованного в браузерах. В том числе, природой изоляции.

Проблема № 1: та же, что и для кастомных элементов — Shadow DOM не работает с выключенным JS. Этот факт делает невозможными некоторые сценарии использования, прежде всего SSR.

Кроме того, это также означает проблемы с SEO. В качестве решения в Google советуют Rendertron на базе Puppeteer, который умеет отдавать роботам статику. Мои коллеги в Vaadin его используют. github.com/GoogleChrome/r…

Существует черновик API декларативного Shadow DOM, над которым работает Mason Freed из Google. Реализация есть в Chrome за флагом, недавно о ней вышла статья на web.dev. web.dev/declarative-sh…

Декларативный Shadow DOM для изоляции стилей на примере слайдов @shower_me! Развиваю старую идею, как имитировать почивший <style scoped>, на этот раз без JS, но пока только в Chrome за флагом youtu.be/ZjYKzrBEEuI
Видео с примером использования декларативного Shadow DOM для изоляции стилей недавно опубликовал Вадим Макеев. twitter.com/pepelsbey/stat…

К стабильной версии декларативный Shadow DOM еще не готов. Идет обсуждение рисков, связанных с XSS и санитайзерами. Также пока неясно, что будет с декларативными кастомными элементами. github.com/whatwg/dom/iss…

Проблема № 2: изоляция Shadow DOM создает преграду для связей по ID. В итоге ARIA-атрибуты вроде aria-labelledby не работают для элементов, находящихся по разные стороны shadow root.

О том, как эта проблема проявляется на практике, написал Devon Govett из Adobe. Он поделился выводами из своего эксперимента на тему использования хуков React Aria внутри веб-компонентов. github.com/devongovett/wc…

Решением может стать Accessibility Object Model (AOM). Это целый набор экспериментальных API, которые пока находятся в разработке. Подробнее можно почитать в статье Léonie Watson. 24a11y.com/2019/web-compo…

Одна из идей в рамках AOM — атрибут, позволяющий явно указывать ID элементов, к которым необходим доступ извне. Что-то вроде атрибута exportparts, который доступен для CSS Shadow Parts. github.com/WICG/aom/issue…

Проблема № 3: изоляция затрагивает также и элемент <form>. Если кнопка в форме находится внутри shadow root, отправлять форму она не сможет. Пример приводит в своей статье Poul H. Hansen. hjorthhansen.dev/shadow-dom-and…

Справедлива эта проблема и для элементов <input> внутри Shadow DOM. В прошлом Polymer предлагал компонент для сериализации форм с рекурсивным обходом вложенных shadow root. github.com/PolymerElement…

Проблема № 4: отсутствие API для работы с выделенным текстом внутри Shadow DOM при использовании window.getSelection(). Это актуально для WYSIWYG-редакторов вроде CKEditor, Quill и Trix. github.com/WICG/webcompon…

В Chrome этот метод реализован на shadow root, в Firefox работает глобальный метод. Но в Safari действует изоляция, и getSelection() не возвращает данные об элементах внутри Shadow DOM. bugs.webkit.org/show_bug.cgi?i…

Sam Thorogood из Google написал экспериментальный полифилл, позволяющий обойти это ограничение в Safari. Для одного из компонентов Vaadin я интегрировал этот полифилл в форк Quill. github.com/GoogleChromeLa…

Проблема № 5: проблемы с автозаполнением форм. В баг-трекере Chromium есть issue на эту тему, и ему уже больше трех лет. В общем, с формами у Shadow DOM как-то совсем не задалось. bugs.chromium.org/p/chromium/iss…

Затрагивает эта проблема и браузерные расширения, прежде всего менеджеры паролей. Каждому из них потребуется соответствующий фикс. Например, в 1Password он уже реализован. 1password.community/discussion/791…

Проблема № 6: изоляция стилей не работает в случае с font-face и keyframes. Решение этой проблемы требует стандартизации. На данный момент font-face в Shadow DOM использовать нельзя. github.com/w3c/csswg-draf…

Проблема № 7: сторонние скрипты. Google Tag Manager, A/B тесты, аналитика и все, что так любят добавлять на сайт маркетологи, очень плохо дружит с Shadow DOM. Об этом тоже важно помнить.

@jsunderhood Как тестировать страницу с ShadowDOM при помощи Selenium? Вроде был /deep/ комбинатор, но он же deprecated?
Проблема № 8: тестирование. На сегодняшний день Shadow DOM уже поддерживается в Cypress, TestCafe, WebdriverIO и Playwright. В Selenium поддержка пока не реализована. twitter.com/justboriss/sta…

@jsunderhood Как может быть поддержка в WebdriverIO, но не в Selenium? У них же один и тот же webdriver protocol
Насчет WebdriverIO: поддержка Shadow DOM появилась в версии 5.5.0 и реализация у них своя (поскольку в протоколе WebDriver нет стандартизированного API). webdriver.io/blog/2019/02/2… twitter.com/justboriss/sta…

Есть issue на эту тему, где в том числе поделился опытом Diego Ferreiro Val из Salesforce. Согласиться на добавление API, которое бы нарушало изоляцию, разработчики браузеров не готовы. github.com/WICG/webcompon…

Вроде бы, все основные проблемы перечислил. Есть и другие — например, в Chrome в Shadow DOM не работает перевод страницы. bugs.chromium.org/p/chromium/iss…

Еще есть баг на iOS, связанный с кнопками быстрого перехода между полями формы в Shadow DOM. Он был исправлен совсем недавно. bugs.webkit.org/show_bug.cgi?i…

В качестве заключения: проблем у Shadow DOM по-прежнему много, и о них желательно знать заранее (или придется городить костыли). Неспроста YouTube использует полифилл даже в Chrome.

Да, чуть не забыл: реклама же! Мне однажды тоже довелось встретить div с shadow root в рекламном баннере Яндекс-почты. Для блокировщиков это проблема. twitter.com/faramo_zayw/st…

Так или иначе, статистика показов страниц в Chrome Platform Status говорит сама за себя: по сравнению с кастомными элементами, у которых около 10%, Shadow DOM почти вдвое менее популярен. chromestatus.com/metrics/featur…

🔥Тред (Сергей Куликов)
В завершение темы Shadow DOM — небольшой тред о слотах и композиции, которые я как-то обошел стороной.

Элемент <slot> является частью Shadow DOM и включен в стандарт WHATWG. Во времена “версии 0” в Chrome ему предшествовал элемент <content>, работавший несколько иначе. developer.mozilla.org/en-US/docs/Web…

Назначение <slot> — проекция контента из так называемого “light DOM” (снаружи) в определенную точку внутри Shadow DOM. За примерами в очередной раз отсылаю к учебнику Ильи Кантора. learn.javascript.ru/slots-composit…

Компонент с Shadow DOM может применять стили к переданным в слоты элементам с помощью псевдоэлемента ::slotted(). Важный момент: использование сложных селекторов не допускается. developer.mozilla.org/en-US/docs/Web…

На практике это означает, что если внутрь слота передать элемент <ul>, то стили к самому списку с помощью ::slotted(ul) применить можно, а вот ::slotted(ul li) использовать не получится.

При добавлении или удалении элементов на элементе <slot> возникает событие slotchange. Оно не является синхронным и срабатывает в конце микротаска, после Mutation Observer. developer.mozilla.org/en-US/docs/Web…

Кстати, лучший способ более детально ознакомиться с API, о которых я рассказываю (в том числе и слотами) — проект web-platform-tests. Для Shadow DOM там есть целый набор тест-кейсов. github.com/web-platform-t…

Интересный факт: Svelte 3 отказался от нативных слотов, потому что контент в них попадает сразу, тогда как по мнению Rich Harris для фреймворка удобнее возможность отложенного рендеринга.

На мой взгляд, это достаточно показательный момент: фреймворки предпочитают свою модель композиции, поскольку она лучше решает их задачи, и привносят свои абстракции (scoped slots).

Vue поддерживает компиляцию в кастомные элементы, используя при этом нативные слоты (но scoped slots не поддерживаются). github.com/vuejs/vue-web-…

Четверг


Одна из возможных перспектив применения слотов — кастомизация нативных элементов (в первую очередь, select). Этой теме посвящен черновик Custom Control UI от разработчиков Edge. github.com/MicrosoftEdge/…

Этот проект находится в стадии прототипирования (intent to prototype был опубликован в августе этого года). Кроме слотов, среди идей упоминаются и CSS Shadow Parts для нативных элементов. groups.google.com/u/0/a/chromium…

Заодно стоит упомянуть проект Open UI, в рамках которого разработчики Edge, Salesforce и Chrome обсуждают улучшения стандартных элементов интерфейса, представленных в HTML. open-ui.org

🔥Тред (Сергей Куликов)
На сегодня все. Завтра поговорим про элемент <template> и его перспективы, а также о разработке на ES-модулях в браузере.

Сегодня начнем с треда про элемент <template>. Раньше он считался частью веб-компонентов, хотя сейчас о нем вспоминают реже.

Содержимое <template> является инертным: элементы не попадают в DOM, скрипты не выполняются, стили не применяются. По сути это декларативный способ создания DocumentFragment. developer.mozilla.org/en-US/docs/Web…

Получить содержимое <template> можно с помощью свойства content, используя один из двух методов: content.cloneNode(true) или document.importNode. На практике разница обычно несущественна. developer.mozilla.org/en-US/docs/Web…

На первый взгляд этот элемент прост, и появился он в браузерах намного раньше Custom Elements и Shadow DOM. Тем не менее, его внедрение потребовало изменений HTML-парсера. caniuse.com/template

Для IE11 есть полифилл, который имеет ограничения. Например, нельзя использовать <template> внутри элементов <table> и <select>: в обоих случаях IE удаляет незнакомый ему тег. npmjs.com/package/@webco…

Темплейты в Polymer использовались с кастомным синтаксисом для data binding. Вместе с HTML Imports это позволяло писать в HTML вообще все. Про типизацию шаблонов тогда никто не думал.

Впрочем, создавать <template> можно и в JavaScript. Это полезно для ванильных кастомных элементов: по сравнению с использованием innerHTML темплейты быстрее (нет лишних затрат на парсинг).

Именно этот способ использует библиотека lit-html от команды Polymer, синтаксис которой основан на tagged template literals. Подробнее о принципах ее работы можно почитать в ее wiki. github.com/Polymer/lit-ht…

Замечу, что lit-html в этом плане не уникальна. Более того, Andrea Giammarchi утверждает, что в hyperHTML он реализовал этот подход раньше, а разработчики из Google позаимствовали его идею. gist.github.com/WebReflection/…

Теперь о перспективах <template>. Недостаток этого элемента в том, что он не предоставляет API для интерполяции значений. В качестве возможного решения предложен черновик Template instantiation. github.com/WICG/webcompon…

Наряду с AOM, это один из примеров инициативы со стороны WebKit. Из моих предыдущих твитов могло сложиться впечатление, что все инновации двигает Chrome, но чаще это плод совместных усилий.

Развитием идеи Template instantiation является новый черновик DOM Parts за общим авторством разработчиков WebKit и Chrome. Это API на первый взгляд имеет много общего с устройством lit-html. github.com/WICG/webcompon…

В перспективе DOM Parts могут сделать манипуляции с DOM более эффективными и упростить написание библиотек вроде lit-html. Но пока эта идея в стадии обсуждения и к ней есть ряд вопросов. github.com/WICG/webcompon…

Напоследок упомяну еще один черновик, предложенный после удаления HTML Imports. Он называется HTML modules и в теории придаст новую жизнь декларативному применению <template>. github.com/WICG/webcompon…

Как и CSS-модули, которые я упоминал вчера, этот черновик долгое время был заблокирован, но теперь возобновление работы над ним стало возможным благодаря переходу Import Assertions на Stage 3. github.com/tc39/proposal-…

Возможно, в будущем <template> станет опорой для неких новых конструкций, меняющих наши представления об HTML. Но полезен он и сейчас, что подтверждает статистика Chrome Platform Status. chromestatus.com/metrics/featur…

🔥Тред (Сергей Куликов)
Тред о разработке на ES-модулях в браузерах.

Небольшое предисловие: Polymer всегда продвигал идею bundler-free разработки и HTML Imports в нее хорошо вписывались. Компоненты и целые приложения было принято разрабатывать без webpack.

Polymer 1 был полностью написан на ES5, поэтому Babel тоже не требовался — достаточно было поднять nginx. Идиллию нарушал режим "F5 monkey" и секунды ожидания обновления страницы.

Кстати, еще команда Polymer пыталась продвигать идею HTTP/2 server push с помощью prpl-server. Популярности этот подход не приобрел, а теперь HTTP/2 push и вовсе удаляют из Chrome. groups.google.com/a/chromium.org…

К моменту выхода Polymer 3 в 2017 году все основные браузеры реализовали поддержку ES-модулей. Переход на них был логичным решением, позволяющим не зависеть от бандлеров и в дальнейшем. polymer-project.org/blog/2017-08-2…

На сегодняшний день ES-модули имеют более 90% поддержки. Они реализованы везде, кроме IE11 — для него многие советуют собирать отдельный ES5-бандл с атрибутом nomodule. caniuse.com/es6-module

Единственная проблема — отсутствие поддержки bare module specifiers, стиля импортов Node.js. Браузеры понимают только относительные пути к файлам. Об этом написал Damien Seguin. medium.com/@dmnsgn/es-mod…

В будущем эту проблему планируется решить с помощью Import Maps. Этот черновик предложил Domenic Denicola из Google, недавно о нем также позитивно высказались представители Mozilla. github.com/WICG/import-ma…

Полифилл пропозала Import Maps для браузеров с поддержкой ES-модулей предоставляет пакет ES Module Shims. npmjs.com/package/es-mod…

Две статьи о разработке на ES-модулях написал Lars Den Bakker из проекта Open Web Components. В первой из них он описывает их синтаксис, в том числе dynamic imports и import.meta. dev.to/open-wc/develo…

Вторая часть статьи посвящена проекту es-dev-server. Это сервер для локальной разработки на Koa, который поддерживает ES-модули и предоставляет удобную систему плагинов. dev.to/open-wc/develo…

es-dev-server пользуется популярностью среди разработчиков веб-компонентов на lit-element. Команда Polymer рекомендует его как замену утилиты polymer-cli, поддержка которой прекращена.

Новая версия es-dev-server получила название Web Dev Server. Он поддерживает некоторые плагины Rollup, а также предоставляет плагин на базе esbuild для компиляции TypeScript на лету. modern-web.dev/docs/dev-serve…

Есть и другие похожие инструменты. Пожалуй, самый известный — Snowpack, который разрабатывает Fred K. Schott. Между прочим, в прошлом он работал над бандлером и CLI в команде Polymer. snowpack.dev

Идея Snowpack в двух словах — запустить Rollup один раз после npm install, скомпилировать все зависимости в папку web_modules и далее подключать их оттуда, используя относительные пути.

С выходом версии 2.0 Snowpack превратился в систему сборки с поддержкой TypeScript, JSX, React, Vue и Svelte и бандлером для продакшна. Подробнее можно почитать в анонсе релиза. snowpack.dev/posts/2020-05-…

Кроме Snowpack, Fred K. Schott также запустил Skypack — поисковую систему и CDN для пакетов, поддерживающих ES-модули. Проекту уже больше года, до ребрендинга он носил название Pika. skypack.dev

Опытом разработки на ES-модулях с использованием Snowpack поделился Bryan Braun. В статье описаны ряд аспектов: зависимости, CSS, кэширование. Отдельно упомянуты плюсы и минусы. bryanbraun.com/2020/10/23/es-…

As I was going to bed, I had an idea about a no-bundler dev setup (using native browser ES imports), but with support for Vue SFCs with hot reload. Now it's almost 6AM and I have PoC working. The hot reload is so fast it's near instant.
Теперь еще об одном проекте. В апреле идеей разработки на ES-модулях загорелся Эван Ю. Отсчет можно вести с этого твита. Ради этого проекта Эван даже отвлекся на время от работы над Vue 3. twitter.com/youyuxi/status…

@youyuxi seems you got quite inspired by es-dev-server 🤗 is there maybe room to collaborate? having full support for vue within es-dev-server via a middleware or a "plugin" would certainly sounds great 💪 now it seems more like becoming a "fork" with baked in vue features? 🤔 pic.twitter.com/sQdHednPCj
Дальше, по-видимому, Эван увидел мой ретвит, где я упомянул es-dev-server. Вскоре в его проекте появились заимствованные оттуда идеи, вроде использования es-module-lexer и lru-cache. twitter.com/daKmoR/status/…

Сегодня Vite находится в стадии release candidate. Его документация содержит упоминания es-dev-server и Snowpack с обзором отличий в решаемых задачах и используемых подходах, прежде всего HMR. github.com/vitejs/vite#ho…

Кстати о HMR: авторы Vite и Snowpack при участии Jovi De Croock (Preact) работают над черновиком реализации соответствующего API для разработки на ES-модулях на основе import.meta. github.com/snowpackjs/esm…

Замечу, что эта спецификация HMR имеет ряд отличий от реализации Hot Module Replacement в webpack. Их сравнение приводит Tobias Koppers (автор webpack) в своем комментарии к этому issue. github.com/snowpackjs/esm…

Недавно экспериментальная поддержка HMR на основе этой спецификации появилась также и в Web Dev Server в качестве плагина. Советую взглянуть на примеры в документации. modern-web.dev/docs/dev-serve…

До сих пор я говорил об инструментах. Но есть и еще один момент: многие пакеты в npm до сих пор не имеют ESM-версии. В качестве возможного решения Joel Denning создал проект esm-bundle. medium.com/@joeldenning/a…

В рамках esm-bundle для некоторых популярных пакетов настроена автоматическая публикация. Вот, например, версия Chai на ES-модулях, которую мы в Vaadin используем с Web Test Runner. npmjs.com/package/@esm-b…

Также стоит упомянуть утилиту Dual Publish от Андрея Ситника. Она помогает настроить публикацию ESM и CommonJS версий. github.com/ai/dual-publish

Подводя итоги, скажу, что на сегодняшний день ES-модули можно использовать не только как compilation target, но и в процессе разработки. Думаю, этот подход будет развиваться и дальше.

На сегодня все. Завтра поделюсь опытом поддержки библиотеки компонентов в open source. Кроме того, в честь пятницы 13-го будет небольшой тред на тему человеческого фактора.

Пятница


@jsunderhood для всех интересующихся esm в браузерах, мы недавно создали канал на дискорде, приходите похоливарить: discord.gg/sDcJydJ
В комментариях поделились ссылкой на дискорд о ES-модулях. twitter.com/vovacodes/stat…

🔥Тред (Сергей Куликов)
Кстати, пользуясь случаем, приглашаю в русскоязычный чат о веб-компонентах в Telegram (приходите холиварить и к нам тоже): t.me/webcomponents_…

В этом треде поделюсь опытом трех лет поддержки библиотеки веб-компонентов в open source и расскажу о превозмогании трудностей.

Как я уже упоминал, компоненты Vaadin написаны на Polymer. Почти весь код до сих пор на Polymer 2 и поэтому использует Bower. Так что поддерживать приходится больше 40 репозиториев на GitHub.

Для конвертации в Polymer 3 у нас есть CLI-утилита. Любая версия компонента доступна в Bower и npm одновременно, но при этом код там разный. С точки зрения semver это выглядит весьма странно.

Подход, где каждый компонент — отдельный npm пакет, имеет свои недостатки. Например, нужно следить за версиями, чтобы избежать дубликатов зависимостей, иначе в приложении будут ошибки.

Кроме того, мы поддерживаем несколько минорных версий и иногда бэкпортим фиксы. В таких случаях важно следить за npm dist-tag, чтобы более ранняя минорная версия не получила тег latest.

Количество репозиториев тоже создает сложности. Мажорные версии нужно релизить в правильном порядке, обновляя при этом зависимости. У нас есть скрипты, чтобы не делать все вручную.

Надеюсь, в будущем удастся перевести разработку библиотеки в монорепу и унифицировать версии. Для API компонентов на Java мои коллеги это уже сделали, это сильно упростило процесс релиза.

Задача осложняется тем, что у Vaadin есть LTS-релизы и компоненты на Polymer 2 нашей команде предстоит поддерживать еще несколько лет (хотя версия на HTML Imports по факту уже год как deprecated).

Много репозиториев = много билдов в CI. Мы пока используем Travis, а у него лимит 5 free jobs на организацию. Отправив PR, можно идти пить кофе, хотя чаще всего приходится ждать сильно дольше.

Недавно в Travis объявили об изменении ценовой модели. Вкратце, безлимит для open source проектов заканчивается. Дополнительные бесплатные минуты обещают выдавать после рассмотрения запроса. blog.travis-ci.com/2020-11-02-tra…

Мы постепенно переходим с Travis на GitHub Actions. Пока общее впечатление положительное. Огорчает отсутствие возможности перезапустить отдельный job (можно только workflow целиком). github.community/t/ability-to-r…

Для тестирования мы используем SauceLabs. У них есть бесплатный план для open source по запросу. Правда, как-то раз от них пришел email с жирным намеком, что их щедрость имеет свои границы.

@jsunderhood Как у вас работают скриншотные тесты? Визуальный дифф в консоль не вывести. Как смотреть результаты сравнения в Travis и GithubActions?
Насчет тестов скриншотами: с этим у нас пока все печально. Каждый раз приходится смотреть локально, что именно сломалось. Надеюсь, когда-нибудь у нас дойдут руки интегрировать Argos CI. twitter.com/justboriss/sta…

При разработке на GitHub важен удобный project board. Несколько лет назад мы использовали Waffle, идеально подходивший для наших задач. К сожалению, этот сервис уже давно недоступен.

После Waffle пробовали GitHub Projects, там оказалось несколько недостатков: не было возможности связать issue и PR, отсутствовали status checks. Пришлось перейти на ZenHub как меньшее зло.

Разработка продукта в open source подразумевает коммуникацию с теми, кто его использует. Это полезно в смысле выявления багов, также можно получить полезный фидбек, иногда он вдохновляет.

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

Для общения у нас есть канал в слаке Polymer Project. Там иногда появляются мейнтейнеры lit-html, в том числе Justin Fagnani. Свой канал там есть также и у проекта Open Web Components. polymer-project.org/slack-invite

В прошлом мы в Vaadin также использовали Gitter. На мой взгляд, он был удобен только ссылками на issue. Никаких особых улучшений за 3 года там не появилось. В итоге недавно мы перешли на Discord. discord.gg/PHmkCKC

Немного о процессах. Раз в неделю мы просматриваем новые issue, стараемся на них отвечать и добавляем метки. Также каждую неделю один из нас поочередно следит за вопросами в Slack и Discord.

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

Когда issue много, они превращаются в груз, который производит угнетающее впечатление. Простой способ "решить" проблему — настроить stale bot, но мы пока еще к этому не готовы.

Единственный способ разгрести груду тикетов — постоянство и автоматизация. Помогает даже использование меток. Еще очень важно наличие в проекте issue template, а лучше нескольких.

Улучшения требуют времени. У нас в Vaadin для этого есть Community Friday: пятница в конце двухнедельного спринта. В этот день можно заниматься и своими опенсорс-проектами, это приветствуется.

🔥Тред (Сергей Куликов)
@jsunderhood @intercom Похоже у вас прямо гигантский тул. Я записываю все такие интересные штуки, но по сравнивать не хватает времени.Даже какой-то конструктор визуальный есть! Жаль что завязано на java. Не знаешь про планы сделать lang agnostic?
Отвечаю на вопрос о визуальном конструкторе Vaadin: сейчас в разработке плагин для VSCode для приложений на lit-element и TypeScript. Когда будет альфа, поделюсь в личном аккаунте. twitter.com/mxtnr/status/1…

Тред в честь пятницы 13-го. О человеческом факторе и багах.

Для начала простой факт: у фреймворка Vaadin есть версия 14.1.5. Следующая за ней имеет номер 14.1.16. К счастью, это был всего лишь патч-релиз, и обращаться в npm для отката мы не стали.

В тот раз отличился не я, но в моей карьере тоже бывало всякое. До перехода во фронтенд я больше 7 лет работал в IT-отделе крупного банка как человек-CRON, ну и еще немного админил базы данных.

Работа включала в себя применение SQL-скриптов, присылаемых разработчиками по скайпу. Возможно, вы слышали шутку про тех, кто запускал UPDATE без WHERE и тех, кто еще нет. Я запускал.

@jsunderhood Не очень понятен смысл твита. В чем баг? Версия же все равно выше
Смысл в том, что это могла быть и мажорная версия. Менеджмент вряд ли бы этому обрадовался. Как известно, из npm после случая с left-pad крайне проблематично что-то удалить. twitter.com/meafmira/statu…

Более 7 лет я нажимал .bat-файлы и вводил нужные даты. Утром, под конец 12-часовой ночной смены, это требует чуть больше внимания, чем обычно. В общем, трёхтысячные годы иногда случались.

От человеческого фактора не застрахован никто. Я достаточно долго был подвержен такому риску, хотя это конечно же не идет ни в какое сравнение с ситуациями, где на кону человеческая жизнь.

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

Прошло почти 5 лет с тех пор, как я сменил профессию. Но и сейчас я каждый раз тщательно проверяю версии и на секунду испытываю тревогу, когда запускаю утилиту, делающую npm publish.

В целом фронтенд намного спокойнее. Хотя тут можно, например, ошибиться в названии переменной. Однажды я так и сделал, в итоге у нас больше 2 месяцев не работал сбор анонимной статистики. github.com/vaadin/vaadin-…

По крайней мере, теперь мне не приходится чинить авралы. Хотя изредка они случаются по вине браузеров. Например, в Chrome 65 при использовании нашего <vaadin-grid> крашилась страница. github.com/vaadin/vaadin-…

@jsunderhood Не значит ли это что больше 2х месяцев это никого не интересовало?
Разумеется. Иногда бывает и такое. Это как раз то, к чему я клоню: если уж проблему не удалось предупредить, ее нужно быстро распознать. Тот же баг Chrome мы могли заметить еще в Canary. twitter.com/shuvalov_js/st…

А еще о проблемах надо говорить. Я упоминал, что часть проектов мои коллеги перенесли в монорепозиторий. До этого я показал менеджменту, сколько времени уходило на ручную работу.
notion image

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

🔥Тред (Сергей Куликов)
На этом на сегодня закончу. На выходные заготовленных тем у меня нет, но поделюсь некоторыми материалами о веб-компонентах.

Суббота


Как и обещал, делюсь полезными материалами о веб-компонентах.

Доклад Jan Miksovsky “Creating Customizable Web Components” с описанием некоторых приемов из библиотеки компонентов Elix. youtu.be/O0Y5QaZPIek

Доклад “Web Component Styling & Theming” от Justin Fagnani. Советую тем, кому интересно больше узнать о приемах стилизации Shadow DOM — я на этой неделе коснулся их лишь в общих чертах. youtu.be/FM7ROEVPA4k

Shadow DOM in depth — неплохое чтиво, где некоторые моменты на мой взгляд изложены чуть более подробно и наглядно, чем на MDN и в учебнике Кантора. Например, хорошо описаны слоты. github.com/praveenpuglia/…

Shipping Web Components in 2020 — довольно интересная статья, в которой Joe Pettersson из Banked.js делится опытом использования веб-компонентов для создания встраиваемых виджетов. medium.com/@banked/shippi…

Looking back on five years of web components — еще более подробная статья от Joe Gregorio о том, как команда Skia попробовала Polymer, но отказалась от него в пользу ванильных кастомных элементов. bitworking.org/news/2019/07/l…

Web Components punch list — простой чеклист доступности для кастомных контролов (в том числе, веб-компонентов) от Steve Faulkner. В качестве примера использован нативный <button>. developer.paciellogroup.com/blog/2014/09/w…

Storybook for web components on steroids — статья от Thomas Allmer из проекта Open Web Components о создании storybook-prebuilt: сборки Storybook для разработки на ES-модулях с es-dev-server. dev.to/open-wc/storyb…

Очень подробная статья от David Lorenz о проблеме реализации изоморфного рендеринга веб-компонентов на примере Vue. itnext.io/a-deep-analysi…

Статья от Jan Miksovsky о нюансах, которые нужно учитывать и о задачах, которые приходится решать, создавая свой combo-box. component.kitchen/blog/posts/bui…

Много статей и примеров есть в подборке Web Components the Right Way — это awesome-list, который я мейнтейню уже почти два года. github.com/mateusortiz/we…

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

Воскресенье


В завершение недели собираю все треды о веб-компонентах в один.

Тема первого дня — кастомные элементы. Как в узком смысле (часть стандарта HTML), так и в широком (framework-agnostic подход к написанию компонентов и приложений на их основе).
Кастомные элементы: знакомство. twitter.com/jsunderhood/st…

Возможны, вы заметили, что до сих пор я избегал термина “веб-компоненты”. Думаю, тред на эту тему будет не лишним.
О том, почему не взлетели веб-компоненты. twitter.com/jsunderhood/st…

Тред о применении кастомных элементов в 2020. С момента релиза Firefox 63 прошло почти два года, в Safari поддержка появилась еще раньше. Так что уже можно делать некоторые выводы.
О применении кастомных элементов в 2020. twitter.com/jsunderhood/st…

Первый тред на сегодня — о том, нужны ли кастомным элементам библиотеки и в каких случаях можно обойтись vanilla JS.
Нужны ли кастомным элементам библиотеки? twitter.com/jsunderhood/st…

Тред про кастомные элементы без зависимостей, с примерами из личного опыта. И заодно немного о best practices.
Опыт написания кастомных элементов без зависимостей. twitter.com/jsunderhood/st…

Тред о кастомных элементах на TypeScript и тестировании.
Немного о TypeScript и тестировании кастомных элементов. twitter.com/jsunderhood/st…

Я обещал рассказать о не решенных проблемах кастомных элементов. В этом треде перечислю основные из них.
Проблемы кастомных элементов. twitter.com/jsunderhood/st…

Сегодняшняя тема — Shadow DOM, его возможности и ограничения. Начнем с треда о главной проблеме, которую Shadow DOM призван решить: глобальный неймспейс и отсутствие в CSS изоляции.
Изоляция стилей в Shadow DOM. twitter.com/jsunderhood/st…

Кроме изоляции стилей, Shadow DOM влияет и на то, каким образом они добавляются на страницу. Тред о том, что это значит на практике и каких улучшений стоит ждать в обозримом будущем.
Особенности подключения CSS в Shadow DOM. twitter.com/jsunderhood/st…

Еще один важный аспект Shadow DOM — кастомизация стилей. При наличии изоляции это становится проблемой, поскольку некоторые стили надо переопределять. Небольшой тред на эту тему.
Кастомизация и CSS Shadow Parts. twitter.com/jsunderhood/st…

Тред про ограничения Shadow DOM и связанные с ними проблемы.
Ограничения и проблемы Shadow DOM. twitter.com/jsunderhood/st…

В завершение темы Shadow DOM — небольшой тред о слотах и композиции, которые я как-то обошел стороной.
Композиция и слоты в Shadow DOM. twitter.com/jsunderhood/st…

Сегодня начнем с треда про элемент <template>. Раньше он считался частью веб-компонентов, хотя сейчас о нем вспоминают реже.
Элемент <template> и его перспективы. twitter.com/jsunderhood/st…

Тред о разработке на ES-модулях в браузерах.
Разработка на ES-модулях в браузерах. twitter.com/jsunderhood/st…

Как и обещал, делюсь полезными материалами о веб-компонентах.
Полезные материалы о веб-компонентах. twitter.com/jsunderhood/st…

🔥Тред (Сергей Куликов)
Веб компоненты должны были упростить веб, но: - их криво задизайнили (за 10 дней видимо по традиции) - поспешили внедрить в браузеры - спустя годы, наконец, поняли где накосячили - теперь придумывают костыли, чтобы ими можно было хоть как-то пользоваться - перспективы не радужные twitter.com/jsunderhood/st…
Неплохое резюме прошедшей недели андерхуда, хотя не могу сказать, что в полной мере разделяю пессимизм автора. twitter.com/jin_nin/stat…

От себя могу только добавить, что погружение в эту сферу принесло мне интересный опыт, которого я мог бы и не получить в проекте на React, куда собеседовался на позицию джуниора весной 2016.

С вами был @iamkulykov. Спасибо всем за внимание и комментарии. Напомню, что у меня есть и англоязычный аккаунт @serhiikulykov. Также меня можно найти в телеграм-чате о веб-компонентах. t.me/webcomponents_…

Ссылки