Понятно и просто про WEB-компоненты и Polymer

16d12bfb3da04ca9a566445b85b01d70.png

Кто я
Я — Александр Кашеверов. По образованию — магистр радиофизики. По профессии — веб-разработчик, работаю в компании DataArt с 2011 года, с 2009 увлекаюсь IT и веб-технологиями.О чем статья, коротко
Рассмотрим, что такое web-components и polymer. Немного поразмышляем на тему развития веба. Посмотрим на технические детали, примеры, поддержку браузерами, тестирование. Коротко, понятно, по делу. С картинками.Вступление
Веб постоянно развивается. Технологии были придуманы и внедрены, исходя из потребностей, актуальных на момент создания. Десять лет назад невозможно было сделать то, что мы реализуем сейчас, и сложно представить, что будет еще через 10 лет.

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

Для уменьшения головной боли хорошо бы, если в контексте веб:

  • CSS не пересекался.
  • Области видимости JS не пересекались.
  • HTML был понятным и читаемым, никаких лишних элементов.


В настоящее время это не совсем так. Относительно JavaScript: приходится следить, чтобы он не работал с global scope и разные компоненты случайно не взаимодействовали друг с другом. В CSS нет и не было инкапсуляции, приходится придумывать методологии вроде MCSS и bem, чтобы ничего лишний раз не сломалось. И наконец, в HTML можно увидеть множество лишних элементов на странице, например, даже сейчас в почте gmail…

ae715acda0b04fe18cad499a3e2682e7.png

Запутанно… Не правда ли?
Фреймворки в той или иной степени внедряют компонентизацию и стараются решить эти задачи. Однако, они так же построены на всё тех же HTML, CSS, JavaScript.

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

История веб-компонентов началась в 2011 году (первое упоминание на github). Кратко — что это:

  • Custom Elements — создание своих html-элементов, дополнение существующих.
  • Shadow DOM — инкапсуляция логики и стилей.
  • Templates — шаблоны на уровне браузера!
  • HTML imports — вместо подключения отдельно разных файлов [css, js, ...] можно подключать один HTML-документ, включающий все остальные файлы.

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

На самом деле, некое подобие веб-компонентов уже было создано давно. Простейший пример — элемент <select> . Для него есть отдельный тег. Взаимодействуя с элементом, появляется выпадающий список и эта логика скрыта от нас, к тому же у него есть свои собственные стили.

<select>
   <option value="Yandex">Yandex</option>
   <option value="Google" selected>Google</option>
   <option value="Yahoo">Yahoo</option>
</select>

2e7f1f8308e04f57a443acb6e593973e.pngac4a558fc2e347a48c6e2d969a2a5cb2.png

Так же и с HTML5 элементами <video> или <audio> .

В этом и есть суть web-компонентов — создание простых и понятных независимых элементов со скрытой логикой, стилями.

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

<link rel="import" href="bootstrap.html">

Web Components — не фреймворк. Это набор технологий, реализованных на уровне браузера.

Web Components — поддержка браузерами & polyfills
На данный момент (ноябрь 2015) три из чеырех технологий находятся в стадии «Working Draft» на W3C.
Так выглядит ситуация на данный момент (ноябрь 2015):

634fe018734b40a3b308ce3c2ed263b3.png

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

С их помощью, поддержка браузерами уже получше.

4c39fef09cbc4a5fadf654281f3729d1.png

На web-странце, полифиллы подключается стандартно в head (до всех скриптов, которые используют веб-компоненты):

<script src="path/webcomponents.js"></script>

Web Components — ссылки
Polymer
Тем временем, Google всё упрощает и развивает. Работа началась осенью 2012 года, судя по истории коммитов на github. Они взяли веб-компоненты, полифилы и создали еще одну надстройку.

Цель Polymer — упростить создание качественных веб-приложений (цитата product manager с конференции Google IO).

Polymer — коротко
Библиотека представляет собой веб-компоненты в основе, полифилы для поддержки старых браузеров, это всё обернуто в целостную более удобную систему с добавлением сахара.

Сехматически это выглядит так:
9bc2bac2be35477c8132b80ff937b7d8.png

Google создал набор готовых компонент и разделил их на логические части:
 

aca4336fd46a4fe1b76627ace79e0dce.png
Основные строительные блоки
<iron-icon>, <iron-input>, <iron-list>, …
3f6bb0bf785e4ef8b33a2c1a2dd5d7c5.png
Элементы на основе iron-elements и material design
<paper-input>, <paper-button>, <paper-tooltip>, ...
2c81896dfa064af084249b2fee4ce96e.png
Коллекция web-компонентов, использующих различные API Google
<google-analytics>, <google-chart>, <google-map>, …
28ce7461c0874f7eade14617e7bb658e.png
Элементы, специфичные для интернет-коммерции
<gold-cc-input>, <gold-phone-input>, <gold-email-input>, ...
90908a2c4fa04a8c89790b4016f06729.png
Элементы для создания анимаций
<neon-animation>
765afa164b7b4dcf83e177d91f7ea09c.png
Элементы, помогающие создать из веб-страницы настоящее приложение
<platinum-bluetooth-device>, <platinum-sw-cache>, <platinum-push-messaging>, ...
a2ba399c4d404cd9b5ab7f9392a022d2.png
Элементы-обертки других библиотек/приложений
<marked-element>


 

Можно заметить, что постоянно фигурирует слово «элемент». Google считает, что для всего можно сделать элемент. «There is an element for that» («для этого есть элемент») — звучит, как слоган в докладах Google IO 2015.

Да, даже для ajax запроса есть элемент. Выглядит так:

<iron-ajax url="some url" handle-as="json" on-response="onResponse"></iron-ajax>

При создании приложений мы сталкиваемся с примерно одинаковыми задачами, и Google предлагает набор готовых строительных блоков для этого. С какой бы проблемой мы не столкнулись — для ее решения есть элемент. «There is an element for that».
Создан каталог готовых Polymer-компонентов.

Polymer — не фреймворк, как и Web Components — не фреймворк. Polymer — это обертка и сахар. Я бы идейно ее сравнил с jQuery. jQuery создана для работы с DOM, а Polymer — для работы с Web Components.

Polymer — тестируемость
Да, он тестируемый, и для этого создана отдельная утилита web-component-tester. Понятное описание.

Пробовал. Работает (при установке могут возникнуть проблемы с Java и Selenium).

Несколько шагов, чтобы заработало:

  • Установить
    npm install -g web-component-tester
    
    

    Написать тест, просто html файл (по-умолчанию, в папке `./test`):
    <!doctype html>
    <html>
    <head>
      <meta charset="utf-8">
      <script src="path/webcomponentsjs/webcomponents.min.js"></script>
      <script src="path/web-component-tester/browser.js"></script>
      <link rel="import" href="path/awesome-element.html">
    </head>
    <body>
      <awesome-element id="fixture"></awesome-element>
      <script>
       suite('<awesome-element>', function() {
          test('is awesomest', function() {
            assert.isTrue(document.getElementById('fixture').awesomest);
          });
        });
      </script>
    </body>
    </html>
    
    

    Запустить тесты:

    wct
    
    
    Polymer — поддержка браузерами
    Polymer — сахар веб-компонента, поэтому и поддержка браузерами точно такая же. Таблицы были представлены выше.

    К слову, у меня так и не получилось запустить на старом Android-телефоне.

    Polymer — оптимизация vulcanize
    HTML imports позволяет быстро и удобно подключить документ в другой документ, но в этом удобстве скрывается и проблема производительности: создается множество http-запросов. Решение есть —- соединить все подключаемые файлы в один. Для этого служит утилита vulcanize.

    Установка:

    npm install -g vulcanize
    
    

    Использование:
    vulcanize index.html > build.html
    
    
    Polymer — starter kit
    Для удобства быстрого создания проектов есть утилита Polymer Starter Kit. После установки сразу доступно множество полезной функциональности.
    Собрано в коробку:
    • Polymer-, Paper-, Iron- и Neon-элементы.
    • Material Design-верстка.
    • Роутинг с Page.js.
    • Юнит тесты с помощью Web Component Tester.
    • Поддержка оффлайн-работы с помощью Platinum Service Worker.
    • Создание билда (включая Vulcanize).
    • ES2015-поддержка.
    Polymer — альтернативы
    Polymer — лишь надстройка над Web Components. Есть и другие подобные продукты:
    Polymer — ссылки
    Polymer — про взаимодействие с библиотеками
    • Angular 2
    • Веб-компоненты будут внедрены в Angular 2: angularjs.blogspot.ru (eng).
    • React
      Официальный представитель от React Sebastian Markbage говорит, что они не будут использовать Web Components совместно с React, т. к. они идеологически разные (декларативный React против императивных Web Components): docs.google.com (eng). Однако, React и Web Components совместимы, в некоторых случаях есть польза: youtube.com (eng).
    • Backbone
      Удобно скрестить с уже готовыми компонентами (Polymer, X-Tags, Bosonic). Используются точно так же, как обычные HTML-элементы. webcomponents.org (eng).
    Web-components & Polymer — примеры
    Рассмотрим простой пример веб-компонента и его Polymer-реализацию:

    Пример чистого веб-компонента:

    <template>
        <span id="multiplier"></span> * <span id="multiplicand"></span> = <span id="result"></span>
    </template>
    
    <script>
    
        (function(window, document) {
            var ownerDocument =  (document._currentScript || document.currentScript).ownerDocument;
            var template = ownerDocument.querySelector('template').content;
            var elementPrototype = Object.create(HTMLElement.prototype);
            var multiplier = 0, multiplicand = 0, result = 0;
            elementPrototype.createdCallback = function() {
                var shadowRoot = this.createShadowRoot();
                var clone = document.importNode(template, true);
                shadowRoot.appendChild(clone);
                this.multiplier = shadowRoot.querySelector('#multiplier');
                this.multiplicand = shadowRoot.querySelector('#multiplicand');
                this.result = shadowRoot.querySelector('#result');
                this.calculate();
            };
    
            elementPrototype.attributeChangedCallback = function(attr, oldVal, newVal) {
                this.calculate();
            };
    
            elementPrototype.calculate = function(){
                multiplier = parseFloat( this.getAttribute('multiplier') );
                multiplicand = parseFloat( this.getAttribute('multiplicand') );
                this.multiplier.textContent = multiplier;
                this.multiplicand.textContent = multiplicand;
                this.result.textContent = multiplicand*multiplier;
            };
            window.MyElement = document.registerElement('element-multiplier', {prototype: elementPrototype });
        })(window, document);
    
    </script>
    
    

    Подключаем в <head> -> <link rel="import" href="element-multiplier.html">
    Используем на странице (в <body> ) -> <element-multiplier multiplier="3" multiplicand="2"></element-multiplier>

    С Polymer будет выглядеть заметно понятней и проще:

    <link rel="import" href="polymer.html">
    
    <dom-module id="element-multiplier">
        <template>
            <span>{{multiplier}}</span> * <span>{{multiplicand}}</span> = <span>{{result}}</span>
        </template>
    </dom-module>
    
    <script>
        Polymer({
            is: "element-multiplier",
            properties: {
                "multiplier"    : { type: Number, value: 0, observer: 'calculate' },
                "multiplicand"  : { type: Number, value: 0, observer: 'calculate' },
                "result"        : { type: Number, value: 0 }
            },
            ready: this.calculate,
            calculate: function(){
                this.result = this.multiplier*this.multiplicand;
            }
        });
    </script>
    
    

    Подключаем в <head> -> <link rel="import" href="path/element-multiplier.html"><script src="path/webcomponents.min.js"></script>
    Используем на странице (в <body> ) -> <element-multiplier multiplier="3" multiplicand="2"></element-multiplier>

    Примеры:

    • pubnub.com — (eng) создание приложения на Polymer.
    • translate.google.com — создан на Polymer.
    • todomvc.com — (eng) пример TODO MVC на Polymer.
    • pubnub.github.io — (eng) анонимный чат на Polymer.
    • github.com — (eng) мое маленькое приложение. Идея проста: когда группа людей делает совместную покупку с одинаковыми вкладами, часто возникает путаница в расчетах долгов, когда скидываются не все сразу. Писал специально, чтобы попробовать Polymer. Там настроены тесты и vulcanize, реализована минификация JS в один файл.
    Спасибо!
    Успехов! Если есть ошибки/замечания/дополнения — пишите.

© Habrahabr.ru