Инкапсуляция, изоляция, разделение, модуляризация, распространение, настройка и документация

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

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

Так что сначала подумать о UI / UX - это отвлечься. Скорее, это забота разработчиков программного обеспечения, предлагающая решение проблем, с которыми сталкиваются разработчики программного обеспечения.

Хорошо спроектированные компоненты имеют семь различных аспектов, которые не зависят от какой-либо структуры (React, Vue, Angular) и строго придерживаются веб-стандартов W3C:

  1. Инкапсуляция пользовательских элементов HTML, чтобы их можно было рассматривать как единое целое.
  2. Изоляция правил CSS для защиты от утечки специфичности.
  3. Разделение работы по созданию шаблонов, декорированию и контролю на трех основных языках Интернета.
  4. Модульность компонентов для обеспечения внутренней области видимости.
  5. Распространение готового продукта, чтобы им можно было поделиться с другими.
  6. Настройка опубликованного продукта для работы в различных настройках.
  7. Документирование того, как все части сочетаются друг с другом.

1. Инкапсуляция

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

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

Объем, который это обеспечивает, означает, что разработчик может избавиться от колбэков на уровне документа onLoad и onUnload.

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

Определение настраиваемого элемента - это простой однострочник:

customElements.define('my-component', MyComponent);

Здесь первый аргумент - это имя настраиваемого элемента, а второй аргумент - это класс JavaScript, который определяет поведение компонента.

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

<body>
    <h1>Hello World!</h1>
    <my-component></my-component>
</body>

Внутренняя работа нового компонента инкапсулируется в этом единственном теге.

2. Изоляция

В течение нескольких лет я игнорировал революцию в компонентах, не полностью осознавая спецификацию shadow DOM, опубликованную W3C. Возможно, это было незнакомое имя с его «однажды удаленным» оттенком.

Теперь я понимаю, что это технология определения области видимости, и отдаю ей должное за решение одной из моих самых серьезных проблем: правил специфичности CSS.

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

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

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

Вот где подходит теневой DOM. Он обеспечивает брандмауэр между элементами, ограниченными document, и элементами, определенными в пользовательском элементе. Преимущества заключаются в безопасности и простоте.

Например, если я объявляю в своем компоненте специальные правила для отображения гиперссылок, эти правила не будут просачиваться и переопределить гиперссылки вне компонента.

Правила стиля можно объявить непосредственно в типе элемента с помощью чего-нибудь очень простого:

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

3. Разделение

Веб-компоненты используют три разных языка: HTML для создания шаблонов элементов, CSS для украшения элементов и JavaScript для управления взаимодействием с пользователем.

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

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

  • Структурная разметка записывается в формате HTML template, который сохраняется в .html файле.
  • Декорации объявляются с помощью правил CSS, которые сохраняются в отдельном .css файле.
  • Сценарий для управления взаимодействием с пользователем написан на JavaScript, который сохраняется в собственном .js файле.

В этом шаблоне инициализация компонента помещается в файл .js и вызывается браузером, когда пользовательский элемент добавляется в DOM.

Затем код JavaScript использует HTTP для динамического извлечения шаблона HTML и правил CSS, добавляя их в теневой корень:

Вуаля! Три языка приведены в гармонию, и разделение интересов сохраняется.

4. Модуляризация

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

JavaScript делает это с помощью операторов import/export. Эта языковая функция устраняет глобальное загрязнение окружающей среды. Преимущество в том, что имена функций могут быть короткими и понятными. Больше не будет initABC и initXYZ, когда подойдет старый добрый init.

Обратите внимание, что здесь я говорю конкретно о модулях ES, а не о старых require утверждениях. При правильном использовании динамические части компонента могут появляться по запросу и загружаться только при необходимости.

Чтобы использовать это в документе HTML, следуйте этому новому шаблону, обязательно указав атрибут type='module':

<head>
    <script src='/my-component.js' type='module'></script>
</head>

Когда это сделано таким образом, каждая часть компонента автоматически получает преимущества кэширования и сжатия, предоставляемые HTTP. Это контрастирует с объединениями «все в одном», которые поставляются сборщиками пакетов.

Для получения дополнительной информации об этом я исследовал уменьшение потребности в сборщиках в новом мире модулей ES в Развертывание модулей завершено.

5. Распространение

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

Для описания компонента достаточно простого package.json файла:

Для установки компонента в корневом каталоге веб-сайта создается отдельный package.json файл с помощью команды npm init.

Команда npm install my-component используется для загрузки компонента и помещения его в каталог node_modules веб-сайта. Для краткости опущен полный механизм настройки npm, публикации пакета и установки пакета.

Преимущества: простая публикация создателем компонента, более широкое распространение в сообществе JavaScript и семантическое управление версиями для потребителя компонента.

6. Настройка

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

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

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

Помните, поскольку теневой DOM изолирует элементы, нет необходимости создавать имена с префиксом, например --my-component-width. Подойдет простое имя, например --width.

Имена переменных должны быть объявлены со значениями по умолчанию внутри файла CSS компонента в :host селекторе, а затем применены к компоненту с использованием синтаксиса var(), например:

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

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

7. Документация

Потребители должны быть обеспечены достаточными инструкциями, примерами и справочными материалами для использования компонента по назначению. Опубликованный readme file должен иметь следующие разделы:

  • Мотивация. Изложение того, какую проблему решает компонент.
  • Возможности. Описание того, как компонент решает эту проблему.
  • Установка. Ссылка на то, где взять компонент и где его разместить.
  • Конфигурация. Описание того, как использовать каждый атрибут, доступный потребителю.
  • Пример. Hello World пошаговое руководство, показывающее, как заставить компонент работать на HTML-странице.
  • Настройка. Список всех переменных CSS, которые можно переопределить.
  • События. Список событий, генерируемых или потребляемых компонентом, и их место в жизненном цикле.

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

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

Для краткости приведенные выше примеры кода обязательно были неполными. Заинтересованный читатель может увидеть все семь аспектов в действии в этих совместимых с W3C веб-компонентах с открытым исходным кодом.

При разработке любого программного обеспечения, выходящего за рамки простого Hello World! приложений, разработчик должен найти способы, чтобы несвязанный код не мешал выполнению текущей задачи.

Это стало катализатором для многих фундаментальных стратегий кодирования, которые мы создали для себя, а именно: функций, объектов, модулей, локальных переменных и других подобных шаблонов области видимости.

Веб-компоненты полностью вписываются в эту область.