Web components что это
Веб-компоненты проще, чем вы думаете
Когда я приходил на конференции и видел презентации на тему веб-компонентов, я всегда думал, что это не только изящно, но и довольно сложно. Тысяча строк JavaScript, чтобы сохранить всего 4 строки HTML. Докладчик или неизбежно скрывал за простыми вещами огромное количество JS кода, или погружался в сложные детали, тогда мои глаза начинали закрываться от скуки, и я начинал думать о том, покрывают ли мои суточные выплаты расходы на закуски.
Однако в недавнем проекте, созданном для легкого изучения HTML (Конечно, путем добавления зомби и глупых шуток), я решил, что необходимо описать каждый элемент HTML в спецификации. Не считая той конференции, я впервые начинал знакомство с и элементами, и, когда я захотел написать что-то интересное о них в проекте, мне пришлось углубиться в тему.
И в процессе углубления я понял: веб-компоненты проще, чем я думал.
Либо веб-компоненты прошли долгий путь развития с тех пор, как я мечтал о закусках на конференции, либо я позволил моему изначальному страху помешать по-настоящему узнать их, а возможно и то, и другое.
Я здесь, чтобы сказать вам: да, вы можете создать веб-компонент. Давайте оставим страх и даже закуски за дверью, чтобы сделать все вместе.
Начнем с
— это HTML элемент, позволяющий создать нам шаблон (HTML структуру для веб-компонентов).
Код
Тогда есть компонент
Код
Код
Использование веб-компонента
Технически, мы закончили писать собственный компонент и уже можем вставить в любое место, где захотим (Примечание переводчика: для полноценной работы компонента необходимо написать немного JS кода, о чем говорится далее).
Код
Стоит обратить внимание, что в названиях веб-компонентов должен быть дефис, чтобы предотвратить конфликт с HTML элементами, которые могут быть добавлены браузерами позже. Это то, о чем вы должны знать, когда дело касается веб-компонентов.
Все еще со мной? Не так уж и страшно, не правда ли? Что ж, минус зомби. Нам еще надо будет немного поработать, чтобы сделать замену возможной, именно здесь мы начинаем знакомство с JavaScript.
Регистрация компонента
Как я уже сказал ранее, вам нужно немного JavaScript кода, чтобы все это работало, но это не очень сложный, многострочный и глубокий код, как я всегда думал. Надеюсь, я смогу убедить вас в том, что все просто.
Вам нужна функция-конструктор, которая регистрирует веб-компонент. Иначе наше компоненты будет как нежить: она есть, но не полностью живая.
Вот конструктор, который мы будем использовать.
Код
Я оставил в коде подробные построчные комментарии, но не объяснил код на последней строке.
Код
Мы здесь делаем много работы. Во-первых, мы берем наш веб-компонент (this) и создаем скрытого шпиона, я имею в виду Shadow DOM. < mode: open >означает, что JavaScript может извне :root обращаться к элементам Shadow DOM и управлять ими, что-то вроде настройки доступа к компоненту через черный вход. Был создан Shadow DOM и мы добавляем к ней узел (Примечание переводчика: HTML Node). Этот узел будет полной копией шаблона, включая все элементы и текст шаблона. С шаблоном, прикрепленным к Shadow DOM из пользовательского компонента, элемент и slot атрибут берут на себя задачу сопоставления содержимого с тем, где оно должно находиться.
Проверьте это. Теперь мы можем объединить экземпляр одного и того же веб-компонента, отображая разный контент, просто изменив один элемент.
Код
Стилизация компонента
Возможно, вы заметили стилизацию в нашем примере. Как и следовало ожидать, у нас есть абсолютно все возможности для стилизации наших компонентов в CSS. На самом деле, мы можем включить
The Zombies are coming!
Таким образом, стили применяются только для компонента, что позволяет изолировать их благодаря теневой модели Shadow DOM.
Я предположил, что пользовательский компонент берет копию шаблона, вставляет контент, который вы добавили, и внедряет его на страницу, используя Shadow DOM. Хотя может показаться, что работа Shadow DOM похожа на обычное DOM дерево, но это не так. Контент в веб-компоненте остается на месте, а теневой DOM как бы накладывается сверху.
И с этого момента контент технически находится вне шаблона, любые селекторы и классы, используемые в шаблонном
Zombie Bob
Код
А вот и результат:
Несмотря на то, что есть еще пару ловушек и нюансов, я надеюсь, вы получили больше возможностей для работы с веб-компонентами, чем несколько минут назад. Возможно, будет хорошо, если вы добавите в свою работу какой-то нестандартный компонент, чтобы прочувствовать их и понять, где их использование имеет смысл.
Web Components. Назад в будущее.
Наверное, каждый frontend разработчик задавался вопросом, какую библиотеку или фреймворк выбрать как основу для своих приложений Angular, React или Vue, но, по сути, у всех современных технологий есть общий трэнд. Мы разбиваем приложение на небольшие компоненты и используем их, строя устойчивую архитектуру. Безусловно, компонентный подход — это одна из страниц в истории frontend, которая перевела разработку на новый уровень. К сожалению, мало говорится о том, что можно использовать компонентный подход на чистом JS, CSS и HTML. Я имею в виду технологию Web Components, появившуюся еще в далеком 2011 году. Давайте разберем на практике из чего состоит Web Components и насколько технология пригодна для использования.
Поддержка браузерами
Самой большой проблемой Web Components было отсутствие поддержки большинством браузеров, и, если посмотреть статистику, стандарт v0 практически нигде не поддерживался. Сейчас ситуация изменилась. Вот актуальная информация на начало 2019 года:
Выглядит действительно круто, демо приложение запустилось в chrome и safari вообще без компиляции.
Microsoft как всегда немного портит общую картину, но есть полифилы.
Из чего состоят Web Components
Начать следует с того, что Web Components объединяет в себе несколько спецификаций. На данный момент это:
Разберем их по порядку.
Custom Elements v1
Позволяет добавить на страницу собственный элемент, содержащий в себе несколько DOM nodes. Вот как это выглядит:
Как видно из кода выше, первым делом нужно создать класс и наследовать его от HTMLElement, затем с помощью customElemens задать ему имя тэга. Важно, что имя должно состоять из 2х частей, разделенных дефисом. Компонент готов к использованию.
HTML templates
С помощью элемента template можно создать шаблон вместе со стилями, который будет позже вставлен в разметку страницы или, в данном случае, в отдельный компонент. Элемент slot указывает, куда будет вставлена разметка, полученная из родителя между открывающим и закрывающим тэгами компонента. Также существует возможность создавать несколько именованных слотов. Вот как это будет выглядеть:
Shadow DOM v1
Shadow DOM позволяет создать изолированное от основного документа DOM дерево со своими инкапсулированными стилями:
Разберем расположенный выше код. Внутри класса TodoButton ключевое слово this указывает непосредственно на класс, т.е. на данный компонент. Метод attachShadow добавляет в компонент корневой элемент DOM дерева, который после становится доступен через this.shadowRoot, и к нему прикрепляется созданный выше шаблон. Вот как будет выглядеть + в chrome devTools:
Создание и распространение событий
Работу с событиями рассмотрим на примере удаления задачи из списка задач.
Так выглядит DOM дерево:
В нем есть компонент задачи ( todo-item), который принимает на вход id, name и completed. Вот как он выглядит изнутри:
В компоненте из шаблона через querySelector происходит получение элемента кнопки удаления, затем через addEventListener добавляется подписка на событие клика по кнопке. После клика компонент распространяет новое событие deleteTodo. Параметр определяет, что данное событие должно всплывать. Теперь можно в родительском компоненте отловить событие deleteTodo:
Благодаря описанному выше свойству bubbles, событие можно отловить на уровне списка и сделать одну подписку, а не добавлять её на каждый item. Через ev.target получаем элемент, который вызвал событие удаления, после чего можно отфильтровать список задач и удалить элемент через removeChild.
Изменение атрибутов компонента
К уже рассмотренному выше приложению в компонент todo-item добавим свойство completed(признак завершенности задачи), которое будет меняться по клику на галку около элемента.
В родительском компоненте, так же как и с удалением, добавляется прослушивание события клика на галку.
В дочернем компоненте отследить изменения можно с помощью хука attributeChangedCallback(attrName, oldVal, newVal), который возвращает три аргумента: название атрибута, старое значение и новое значение. Но по умолчанию изменение атрибутов не наблюдается, и если необходимо отслеживание, то надо добавить атрибут в геттер static get observedAttributes(). Код компонента после изменения:
Тут мы можем отметить потерю типизации. Конечно, в случае с простыми атрибутами это не смертельно, но немного неприятно и затрудняет передачу объектов между компонентами.
Выводы
Технология Web Components поддерживается практически полностью, её будет легко изучить и применить разработчикам, которые использовали хотя бы одну библиотеку с компонентным подходом.
В маленьких и средних проектах смело можно её использовать для кастомизации элементов интерфейса и обходиться без внешних зависимостей.
В больших проектах, конечно, не обойтись без фреймвокров, т.к. они помимо компонентного подхода дают еще окружение, приятные фичи и большое комьюнити, но Web Components можно применить и в них для избавления от legacy кода и миграций (допустим с AngularJs на Angular).
Web Components — будущее Web
Спустя какое время стало ясно, что основная идея Prototype вошла в противоречие с миром. Создатели браузеров ответили на возрождение Javascript добавлением новых API, многие из которых конфликтовали с реализацией Prototype.
Код на стороне клиента становится сложнее и объёмнее. Появляются многочисленные фреймворки, которые помогают держать этот хаос под контролем. Backbone, ember, angular и другие создали, чтобы помочь писать чистый, модульный код. Фреймворки уровня приложения — это тренд. Его дух присутствует в JS среде уже какое-то время. Не удивительно, что создатели браузеров решили обратить на него внимание.
Web Components — это черновик набора стандартов. Его предложили и активно продвигают ребята из Google, но инициативу уже поддержали в Mozilla. И Microsoft. Шучу, Microsoft вообще не при делах. Мнения в комьюнити противоречивые (судя по комментариям, статьям и т.д.).
Основная идея в том, чтобы позволить программистам создавать “виджеты”. Фрагменты приложения, которые изолированы от документа, в который они встраиваются. Использовать виджет возможно как с помощью HTML, так и с помощью JS API.
Я пару недель игрался с новыми API и уверен, что в каком-то виде, рано или поздно эти возможности будут в браузерах. Хотя их реализация в Chrome Canary иногда ставила меня в тупик (меня, и сам Chrome Canary), Web Components кажется тем инструментом, которого мне не хватало.
Стандарт Web Components состоит из следующих частей:
Фрагменты HTML, которые программист собирается использовать в будущем.
Содержимое тегов парсится браузером, но не вызывает выполнение скриптов и загрузку дополнительных ресурсов (изображений, аудио…) пока мы не вставим его в документ.
Инструмент инкапсуляции HTML.
Импорт фрагментов разметки из других файлов.
В Web Components больше частей и маленьких деталей. Некоторые я ещё буду упоминать, до каких-то пока не добрался.
Templates
Концепция шаблонов проста. Хотя под этим словом в стандарте подразумевается не то, к чему мы привыкли.
В современных web-фреймворках шаблоны — это строки или фрагменты DOM, в которые мы подставляем данные перед тем как показать пользователю.
В web components шаблоны — это фрагменты DOM. Браузер парсит их содержимое, но не выполняет до тех пор, пока мы не вставим его в документ. То есть браузер не будет загружать картинки, аудио и видео, не будет выполнять скрипты.
К примеру, такой фрагмент разметки в документе не вызовет загрузку изображения.
Пример работы шаблонов можно посмотреть здесь.
Все примеры в статье следует смотреть в Chrome Canary со включенными флагами:
Для Чего?
На данный момент существует три способа работы с шаблонами:
Минусы такого подхода в том, что браузер попытается “выполнить” код шаблона. То есть загрузить картинки, выполнить код скриптов и т.д.
Минус в том, что приходится работать со строками. Это создаёт угрозу XSS, нужно уделять дополнительное внимание экранированию.
У нет этих недостатков. Мы работаем с DOM, не со строками. Когда выполнять код, также решать нам.
Shadow DOM
Инкапсуляция. Этого в работе с разметкой мне не хватало больше всего. Что такое Shadow DOM и как он работает проще понять на примере.
Когда мы используем html5 элемент код выглядит примерно так:
Но на странице это выглядит так:
Мы видим множество контролов, прогресбар, индикатор длины аудио. Откуда эти элементы и как до них добраться? Ответ — они находятся в Shadow Tree элемента. Мы можем даже увидеть их в DevTools, если захотим.
Чтобы Chrome в DevTools отображал содержимое Shadow DOM, в настройках DevTools, вкладка General, раздел Elements ставим галочку Show Shadow DOM.
Содержимое Shadow DOM тега в DevTools:
Теория Shadow DOM
Shadow Tree — это поддерево, которое прикреплено к элементу в документе. Элемент в этом случае называется shadow host, на его месте браузер показывает содержимое shadow tree, игнорируя содержимое самого элемента.
Фишка shadow dom в том, что стили, определённые в нём с помощью
Зелёный фон в примере получит только `
` внутри shadow tree. То
есть стили «не вытекут» в основной документ.
Наследуемые стили
Авторские стили
Селекторы ^ и ^^
Инкапсуляция это здорово, но если мы всё таки хотим добраться до shadow tree и изменить его представление из стилей документа, нам понадобится молоток. И кувалда.
Селектор div ^ p аналогичен div p с тем исключением, что он пересекает одну теневую границу (Shadow Boundary).
Селектор div ^^ p аналогичен предыдущему, но пересекает ЛЮБОЕ количество теневых границ.
Зачем нужен Shadow DOM?
Shadow DOM позволяет изменять внутреннее представление HTML элементов, оставляя внешнее представление неизменным.
Custom Elements
API кастомного элемента
Прототип должен наследовать HTMLElement или его наследника,
например HTMLButtonElement :
Зачем нужны Custom Elements?
или
- хорошо подходят для низкоуровневой вёрстки, тогда как Custom Elements позволят писать модульный, удобочитаемый код на высоком уровне.
Shadow DOM и Custom Elements дают возможность создавать независимые от контекста виджеты, с удобным API и инкапсулированным внутренним представлением.
HTML Imports
Импорты — простое API, которому давно место в браузерах. Они дают возможность вставлять в документ фрагменты разметки из других файлов.
Object.observe()
Этот метод доступен в Chrome, если включить флаг Experimental Web Platform features.
TODO widget
Согласно древней традиции, вооружившись этими знаниями, я решил сделать простой TODO-виджет. В нём используются части Web Components, о которых я рассказывал в статье.
Добавление виджета на страницу сводится к одному импорту и одному тегу в теле документа.
Заключение
На мой взгляд, Web Components — это следующий шаг. Разработчики смогут создавать интерактивные виджеты. Их легко поддерживать, переиспользовать, интегрировать.
Код страницы не будет выглядеть как набор “блоков”, “параграфов” и “списков”. Мы сможем использовать элементы вроде “меню”, “новостная лента”, “чат”.
Конечно, стандарт сыроват. К примеру, импорты работают не так хорошо, как шаблоны. Их использование рушило Chrome время от времени. Но объём нововведений поражает. Даже часть этих возможностей способна облегчить жизнь web-разработчикам. А некоторые заметно ускорят работу существующих фреймворков.
Некоторые части Web Components можно использовать уже сейчас с помощью полифилов. Polymer Project — это полноценный фреймворк уровня приложения, который использует Web Components.
Ссылки
Eric Bidelman, серия статей и видео о Web Components:
Web Components — это единственное светлое будущее веба. Смиритесь
Вчера вышла [весьма достойная статья про Web Components, и я понял, что не могу не поделиться тем опытом, что я накопил за последние восемь месяцев. Я не буду рассказывать о том, как работать с Веб Компонентами, я расскажу, почему. Поэтому тем, кто не знает об этом стеке технологий, стоит прочитать статью по ссылке выше.
Дело в том, что в июне вышла первая стабильная версия моей библиотеки CornerJS. Начавшись как автономная реализация директив из AngularJS, она постепенно превратилась в более простой — как в использовании, так и в реализации — аналог (неточный, да, я знаю) Пользовательских Элементов из спецификации Веба Компонентов.
Я прошел через большое количество узких мест, а сейчас эта библиотека используется в нескольких больших и не очень проектах в реальных условиях.
Это замечательная, на мой взгляд, в реализации библиотека — я действительно считал ее основным инструментом в разработке, и в последнем проекте (видеопортале) она оказалась важнее jQuery: от него я мог бы отказаться, а от нее нет.
Но я, как человек, внедривший ее в нашу команду, и отказываюсь от нее — мы переходим на Mozilla X-tags для IE9+ сайтов и Polymer для IE10+ сайтов. К счастью, на моей памяти у нас был всего один или два проекта IE8+.
И в этом посте я расскажу, почему веб-компоненты — это не просто будущее веба. А единственное будущее веба.
Как все началось
Предпосылки к подобной архитектуре появлись четыре года назад в Google и Яндекс, при этом сохранился национальный колорит.
Так, в Google появился AngularJS — фреймворк, в котором большая часть логики опиралась на директивы. Почему это так важно? Потому что директивы представляли из себя модули, которые привязывались к html-тэгам, и выполнялись в изолированном окружении этой ноды. Колорит тут заключался именно в том, что Google сохранил верность Java-подобному подходу, и построил все вокруг не-нативных сеттеров и геттеров. С одной стороны это правильно, это был единственный способ сделать «почти честный» колбэк для изменения Представлений, с другой — это привнесло некое неудобство в использовании библиотеки. Впрочем, о чем это мы, мы уже ко всему привыкли, можно сказать. Но в итоге появилось главное: автономные визуальные и не очень элементы, которые можно легко переносить из проекта в проект. Кстати, говорят — я, к сожалению, последние несколько месяцев не отслеживаю прогресс AngularJS — что они уже переехали на почти нативный Object.observe.
А в Яндексе появился БЭМ, Национальная русская идея с JSON и верстальщицами. Я где-то в комментариях выразил мою позицию по отношению к нему: «БЭМ это попытка влететь в светлое будущее, размахивая костылями. С одной стороны, это действительно получилось, с другой — смотреть без смеха или слез невозможно». Впрочем, неделя рОзжыга на тему БЭМ уже прошла, так что не надо в комментариях обсуждать эту тему, прошу. Я просто хотел сказать то, что сам по себе подход действительно достоин восхищения: понять и сделать механику, которая обеспечивает инкапсуляцию и стилей, и скриптов (да, а в ангуляре только скрипты инкапсулируются) — это гениально, а то, как именно это сделано — это дело второе, и те, кому это действительно нужно, давно смирились и пользуются.
В итоге.
… мы имеем то, что имеем: большие команды пришли к осознанию того, что инкапсулироваться и подключаться должны не только библиотеки (привет, requireJS и мой личный фаворит browserify), но в первую очередь — визуальные компоненты на каждой из страниц сайта.
Почему? Да потому что они не относятся к основному потоку программы. Если у вас веб-приложение, как к нему должен относиться рендеринг диаграммы на главной странице? Никак, идеальный для вас вариант это продекларировать в шаблоне, в нужном HTML-тэге входные данные, а дальше оно пусть само работает. Вы правда не хотите думать о том, когда запустить рендер данных, а если вам внезапно захочется динамически обновлять эти данные — тем более не хотите, вам куда удобнее просто добавить какой-нибудь
Вы уже пользуетесь таким подходом, смотрите:
А ядро вашего веб-приложения должно заниматься действительно важными вещами: рендеринг страниц с содержимым, их динамическое обновление, работа с сетью, фоновые процессы, или ИИ и распознавание речи (а почему бы и нет?). Да даже и почти все это в общем-то можно сделать отдельными веб-компонентами.
Модульный веб
Со временем, когда ты начинаешь активно пользоваться библиотеками для веб-компонентов (или БЭМ, с чем согласятся сторонники этого подхода, хотя я чувствую, что они меня уже возненавидели) внезапно приходит осознание того, что единое приложение, как таковое, почти никогда не нужно. Каждая веб-страница — автономная сущность, изолированная от внешнего мира, ей хорошо самой по себе, а приложение — это та сущность, которая остается при переходе между страницами, и ее почти никогда нет. Дело в том, что переходы между страницами могут быть частичными, и часть Пользовательских Элементов может легко и непринужденно остаться на ней, например, плеер или чат.
В итоге получается очень простая вещь: 90-95% веб-сайтов может быть построено только из автономных компонентов, представляющих из себя модули, сочетающие в себе визуальное представление, логику, а так же внешние методы и свойства. Ну и, конечно, они могут содержать в себе другие модули.
Те реализации этого подхода, которые есть сейчас, на самом деле ужасны в части визуальной составляющей. Если в плане логики вы можете спокойно создать комбинированный AMD/npm/безмодульный компонент с неплохим в общем-то набором инструментов, то с визуальным представлением все сложнее: приходится иметь внутри модуля шаблонизатор, пользоваться inline-стилями или вписываться в document.styleSheets, и все равно не можете быть уверенным, что веб-разработчик не заденет своими стилями модуль. Вдруг у него есть какой-нибудь footer a, и он вставляет туда ваш блок лайков?
Привет, компоненты
На базе опыта команд google, mozilla и многих других у них совместно возникло понимание того, что нужно создать возможность реализовать изолированные логиковизуальные модули. Опыт же подсказал им, что действительно очень важно:
Инкапсуляция css
Это возможность полной изоляции css-стилей для того, чтобы стили документа не влияли на отображение модуля. Почему это важно — и так понятно.
Пользовательские методы и свойства
Куча колбэков на каждый чих
конструкторы, деструкторы, и колбэки для изменения атрибутов. Неочевидный момент: есть два колбэка «конструктора». Первый из них отвечает за создание элемента (document.createElement(‘x-tag’)), а второй — за добавление его в DOM-дерево. В случае, если вы просто добавили элемент в верстку — выстрелят оба. Зачем это нужно? Затем, что некоторые действия (например, запуск событий) должны выполняться по добавлению элемента в DOM-дерево. Более того, они должны выполняться по каждому добавлению элемента в DOM-дерево, в том числе если вы перенесете элемент, передав его через appendChild другому родителю.
Шаблоны без выполнения содержимого
Их важность не очень очевидна на первый взгляд, вроде бы «да, все круто, теперь картиночки не будут подгружаться», но идет отрыв от контекста Пользовательских Элементов: люди забывают о том, что они тоже запускаются по добавлению в DOM, и если раньше в каком-нибудь MVVM фреймворке можно было спокойно вставить что-то в качестве шаблона и забыть — с ним ничего не случится, то теперь же нужно учитывать то, что элементы, объявленные в шаблоне, имеют свойство инициироваться, и какой-нибудь
будет запущен с <
Инкапсуляция верстки
Это тоже не полностью очевидный момент. Дело в том, что точно так же стили, на верстку Пользовательского Элемента не должно быть никакого влияния: она должна быть абсолютно автономной, к ней можно «достучаться» только особой, уличной магией — именно для того, чтобы стандартные библиотеки не умели работать с ним.
Однако зачастую атрибутов для конфигурирования элемента бывает недостаточно, и для какой-нибудь диаграммы самым правильным решением будет создать что-нибудь вроде
Поэтому нужно было сделать две вещи: инкапсуляцию реальной верстки и поддержку простейшей (на уровне тэгов) ее шаблонизации. Обе вещи неплохо удались: Shadow DOM представляет собой одновременно как способ инкапсуляции одновременно стилей и структурной верстки, так и простой, но довольно удобный в некоторых местах шаблонизатор.
В той статье не объяснялось, но я попытаюсь прояснить про шаблонизацию: в действительности шаблонизатор Shadow DOM не ограничивается применением тэга в лоб. У него есть атрибут select, и с ним он выглядит примерно так: Этот тэг «вынимает» из host DOM компонента все элементы, попадающие под действие тэга. Соответственно, второй раз этот поиск уже ничего не найдет. Таким образом, написание в реальности просто перенесет содержимое host DOM в composed DOM, а второй тэг уже ничего не сможет перенести, потому что элементов уже нет.
Если кто-то по-прежнему ничего не понял — попробуйте это замечательное демо, которое показывает, как же все-таки работает Shadow DOM.
Во многих публикациях он подвергался резкой критике из-за того, что не обладал какими-либо сверхспособностями вроде итераторов или фильтров, или даже просто возможности вставить элемент дважды. К сожалению, никто особо не тратил на оппонентов время, а надо было бы. Дело в том, что shadow DOM не шаблонизатор в привычном смысле слова: он не создает элементы из шаблонов. Он занимается прямым пробросом элементов. Если вы поместили элемент в host DOM, и изменили его атрибуты, они будут доступны и изменены и в shadow DOM. Если вы поместили один Пользовательский Элемент в другой Пользовательский Элемент, конструктор для вложенного элемента будет вызван всего один раз, и у него не случится внезапного осознания того, что его куда-то перенесли, и надо заново запускать конструктор. Это был единственный возможный разумный вариант для реализации.
Объявление Пользовательского Элемента
Для декларирования подобных элементов не подходил тэг script: фактически, большая часть тэга представляла из себя все же верстку. В некоторых — я бы даже сказал, многих — случаях скриптинга можно в принципе избежать. Поэтому самым разумным решением было расширить спецификацию самого HTML еще одним элементом с немного «особенным» синтаксисом.
Но тут возникает потребность в еще одном решении: как эти элементы кэшировать? Мы не можем подключить их через script, потому что это не тэг script, а значит, нужно создавать спецификацию для другого способа подключения элементов. Так появились HTML Imports.
Подробнее о них я рассказывать не буду, это, конечно, интересно, но статья и так выходит довольно большой.
Сам же выбор подхода с созданием новых тэгов появился по ряду причин, но одной из основных я бы назвал невозможность привязки двух конструкторов к одному и тому же тэгу. В свое время я потратил полдня на то, чтобы отладить директиву лицензионного соглашения. Выглядел тэг как-то так:
Я долго не мог понять, почему у меня не появляется скроллбокс. Причем дебаггер показывал, что он создается… а потом пропадает.
Дело оказалось именно в том, что directive-scrollbox отрабатывает первой. А directive-agreement — второй, и тоже преобразовывает innerHTML.
В итоге
Спецификация Веб Компонентов очень хорошо продумана, и построена из отдельных модулей, которые вместе направлены на одну простую задачу: предоставить действительно удобный способ создания новых HTML-тэгов, в которых инкапсулированы визуальная часть и логика. Это способно в разы ускорить создание веб-сайтов за счет того, что их становится легче подключить, и во многих случаях это можно выполнять верстальщику самостоятельно, без привлечения фронтэнд-разработчиков. Фронтэнд-разработчикам жизнь тоже облегчается, их работа разделяется фактически на две составных части: создание автономных модулей с логикой и большим удобным набором внешних интерфейсом, и создание ядра веб-приложения. При этом вторая деятельность больше относится к senior разработчикам, которые уже устали от создания «клевых анимированных эффектов», а первая гораздо легче парралелится, и гораздо легче тестируется: тестирование переходит от BDD, который довольно долго был основным для веба, к модульному тестированию, в котором тестируется по отдельности каждый компонент.
Механика HTML Imports особенно важна для развития веба, так как почти гарантированно приведет к созданию онлайн-репозитория/CDN с большим количеством библиотек веб-компонентов, а, как мы знаем, централизованные репозитории положительно влияют на качество кода, создаваемое сообществом: все стараются поднять свою репутацию, выдавая качественный код, само сообщество активно развивается, а необходимые модули и библиотеки становится проще найти и подключить. Централизованный же CDN способен обеспечить и более быструю загрузку веб-страниц (это бич наших дней, размер страниц увеличивается быстрее, чем увеличивается пропускная скорость интернета у конечного пользователя).
В итоге почти наверняка через буквально 2-3 года большая часть того, что сейчас представлено библиотеками, будет реализовано в качестве Пользовательских Элементов, потому что это банально удобнее в использовании и поддержки. Слайдеры, responsive изображения, WYSIWYG и Markdown-редакторы, видео с поддержкой караоке, генератор мурлыкающих котиков на canvas, в общем почти все, что есть в вебе, может быть обернуто в Пользовательский Элемент.
Самое смешное, что элемент не обязательно должен быть визуальным: почему бы не сделать что-то вроде такого?
Веб Компонентов дает вам удобный интерфейс для создания пользовательских библиотек, который по крайней мере стандартизирован, и это действительно удобно.
Начните использовать их сегодня.
Попробуйте, вам понравится.
Если вы разрабатываете для IE9+ — вы можете использовать Mozilla X-tags (сейчас у них УПС, пользуйтесь репозиторием)
Если для IE10+ — подключите Polymer и используйте честные Пользовательские Элементы или пользуйтесь более легким синтаксисом и расширением возможностей Веба Компонентов в polymer.js. Искреннее спасибо Google за то, что они очень сильно вложились в Polymer и создали ie10+ (а некоторые даже IE9+) полифиллы для всех составных частей Веб Компонентов.
Я надеюсь, мне удалось рассказать вам, почему все было сделано именно так: я прошел это на своем опыте, с каждой версией библиотеки все больше приближаясь к X-tags, потому что подобный синтаксис является единственно возможной реализацией «реактивного» подхода к работе с визуальными компонентами, и приближаясь к осознанию причин некоторых странных и сложных на первый взгляд вещей.
Послесловие
В последнее время ведется все больше разговоров о том, что веб становится все более фрагментирован. Если вам нужно подключить browserify-модуль и AMD модуль, это вызовет… некоторые проблемы. Некоторые библиотеки адаптированы для TypeScript, некоторые для CoffeeScript (ну ладно, ладно, я знаю, с ними можно работать, но многих CoffeeScript легко может напугать, если нужно будет исправить небольшие баги в какой-нибудь маленькой библиотеке или добавить свои методы). Dart — это вообще отдельный язык, который далеко не идеально взаимодействует с обычным JS. Веб Компоненты могут убрать эту фрагментированность: все компоненты будут совместимы друг с другом, потому что это будет просто HTML. Пусть и с новыми элемнтами. Google может спокойно создавать компоненты на их Dart, вы сможете пользовать icedCoffee, в Facebook продолжат пугать всех своим JSX, а в Одессе таки будут развивать модули на liveScript и дальше.
Вы все равно сможете пользоваться этими библиотеками, потому что у всех их будет один и тот же способ взаимодействовать.
Пожалуйста, начните использовать их сегодня, и вы сделаете веб лучше: любой разработчик сможет использовать вашу библиотеку, вне зависимости, пишет ли он на чистом JS, или на любом из препроцессоров, или вообще не пишет — задумайтесь о том, что слайдер, например, не нужно инициализировать из JS, ему достаточно того, что он будет сконфигурирован через атрибуты и внутреннее содержимое. В конце концов, две трети, наверное, библиотек для jQuery — это просто что-то вроде $().mediaelement(config) и все.