Ни для кого не секрет, хотя не каждый в курсе, что вебкомпоненты — наше будущее. Это будущее ещё не наступило, но уже вот-вот. Один из способов приблизить это будущее — библиотека Polymer от одной малоизвестной корпорации Google. Одна из причин, по которой будущее не наступает — это совместимость с браузерами и вызванное отсутствием этой совместимости падение производительности. Иногда оно незначительное, а иногда критическое.

Библиотека Polymer, скажу с предубеждением, хорошая, код получается красивый и чистый, а вот падение производительности во всё ещё популярном браузере Firefox — то что не сделает её популярной в ближней перспективе, по моему мнению. Ибо кому оно надо возится, если есть другие, более работающие вещи, а поиски в этих ваших в интернетах решения не дают.
Однако может всё же можно что-то сделать? Так точно. Можно!

Если вы дочитали до этого места и не утратили интереса, то скорее всего вы в курсе, что такое Polymer в текущей своей второй версии и как именно он объявляет зависимости и полифилы. Тег <link rel="import">, который для этого используется, и есть корень проблемы, он не поддерживается и никогда не будет поддерживается в Firefox.

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

Что с этим делать, спросите вы? Может есть сборочные инструменты какие? Может команда малоизвестной корпорации уже постаралась?
Сборочный инструмент есть, но в результате у нас не несколько, а один <link rel="import">, в котором ассорти html и тегов script.
Постойте, а как же билд в один js? А никак! Или всё же как-то?

Очередная новость от команды разработчиков была про подготовку третьей версии
Imports use ES6 import syntax, not <link rel="import">.
Templates are defined by providing a template getter that returns a string—not the <dom-module> and <template> elements.

Чистый JS, короче. А теперь посмотрим, как он сделан. Ведь свои компоненты мы всегда можем переписать, а что делать с вендорными iron и paper, например.
Для начала посмотрим, что с ними сделали наши друзья.
iron-icon
iron-form
Они просто автоматически сконвертировали компоненты в чисто яваскриптовые.
Перенесли шаблоны из тега в свойство объекта и обернули компоненты в функцию автоматического добавления.
Ну так любой сможет, поэтому давайте попробуем сами.

Для начала соберём файлы с компонентами в один штатным polymer build, а затем натравим на результат gulp и попробуем получить js.

let cheerio = require('gulp-cheerio');
...
    .pipe(cheerio(
      {
        run: function ($) {
          $('body > div > *').each(function () {
            if (this.tagName === 'script') {
              return;
            }
            let $this = $(this);
            if (this.tagName === 'dom-module') {
              let script = $this.children('script').html();
              let template = $this.children('template').html();
              if (template && script) {
                script = script.replace('Polymer({', "Polymer({_template:`" + template + '`,');
                script = script.replace('static get is()', 'static get template(){return `' + template + '`}static get is()');
                $this.after($('<script>' + script + '</script>'));
                $this.remove();
                return;
              }
            }
            $this.after($('<script>Polymer.addToHead(`' + $.html(this) + '`);</script>'));
            $this.remove();
          });
        }, parserOptions: {decodeEntities: false}
      }))


где код
Polymer.addToHead = (code) => {
  let a = document.createElement('div');
  a.style.display = 'none;';
  a.innerHTML = code;
  document.head.appendChild(a);
};

Должен быть подключен сразу после <link rel="import" href="../../libraries/polymer/polymer.html"/>, ну или как вы там сами себе придумаете.
В результате мы получаем html состоящий исключительно из тегов <script>, что уже намного ближе к желаемому результату.
    .pipe(splitJsCss({
      type: ['js']
    }))
    .pipe(gzip())

И вот у нас уже сжатый js на выходе, который можно подключить как любой другой js так, как это принято в вашем проекте.
Внезапно, вдруг(tm) исчезает задержка в Firefox. Нет накладных расходов на догрузку и парсинг, всё исполняется синхронно. И кешируется согласно общим политикам сайта.

Не могу сказать, что всё это так же изящно, как стрелочные функции в ES6, но библиотекой Polymer стало можно пользоваться гораздо гораздее, чем буквально за час до прочтения этой статьи.

P.S. Есть ли недостатки? Ну если вы особенно хитро раньше подгружали компоненты по требованию, вам теперь придётся самостоятельно следить за двойным исполнением, если конечно оно у вас было.

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

Комментарии (24)


  1. TargetSan
    18.12.2017 22:01

    А можете кинуть ссылку, почему Firefox "никогда не будет поддерживать" этот тег? Или это вендорское MS-style расширение от Google?


    1. sshikov
      18.12.2017 22:13

      https://www.w3.org/TR/html-imports/


      Ну какое-же это вендорское?


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


      1. Punk_UnDeaD Автор
        18.12.2017 22:16

        Да там со всех сторон красавцы. В стиле «это наша песочница и она будет зелёной».
        Google то тоже отказывается от этого тега в полумерах. Надо понимать, потом и из браузера выбросят.


        1. sshikov
          18.12.2017 22:18

          Гугль в смысле разработчики полимера? Нет слов… неужели они все не понимают, что импорты в html и импорты в js — это разные вещи? Что удобно иметь и то, и другое.


  1. Punk_UnDeaD Автор
    18.12.2017 22:08

    platform-status.mozilla.org/#html-imports
    Добавил в статью.


    1. sshikov
      18.12.2017 22:15

      Ну, про "никогда" они кажется все-таки не писали. Пишут, что нет дескать консенсуса по стандартам. Что на мой взгляд — просто чепуха. Когда это статус драфта кого-то останавливал?


      1. SirEdvin
        18.12.2017 22:17

        Статус драфта значит, что пока можно не пилить, а заняться другими делами. Вроде так…


        1. sshikov
          18.12.2017 22:22

          Чтобы потом, когда стандарт утвержден, оказаться едиственным, у кого еще не допилено? :) Всегда и все начинали делать именно в статусе драфта. Мне кажется, это синдром NIH в чистом виде.


      1. Punk_UnDeaD Автор
        18.12.2017 22:18

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


        1. sshikov
          18.12.2017 22:20

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


        1. sshikov
          18.12.2017 22:29

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


          Самое противное знаете что? Что сто лет назад (ну хорошо, не 100, а в 2009 для определенности), в Flex, уже все было как надо. Т.е. можно было в MXML написать xml namespace, и воспользоваться элементами для создания компонент внутри своей разметки, а можно было написать import в AS3 коде, импортировать классы, и создавать компоненты динамически. Т.е. попросту говоря, хочешь статическую компоновку страницы из custom компонент — к своим услугам язык а-ля HTML, хочешь динамически и с финтифлюшками — берешь полноценный язык программирования, и ваяешь на нем.


        1. vanxant
          20.12.2017 04:11

          Mozilla вроде говорила, что у них под флагом есть работающая реализация


  1. vintage
    18.12.2017 23:19

    В итоге от "будущего" ничего и не осталось — собрали всё в js бандл как любой другой фреймворк :-) Как я всегда говорил web-components — мертворождённая технология.


    1. eugef
      19.12.2017 13:58

      HTML imports лишь одна из трех спецификаций, из которых состоят Web-components. Остальные — либо уже реализованы, либо в разработке во всех современных браузерах.

      P.S. В Polymer 3 HTML imports уже не будет из коробки.

      P.P.S. Избавление от HTML imports также очень сильно ускоряет IE и Edge.


      1. Punk_UnDeaD Автор
        19.12.2017 14:04

        Спасибо за P.P.S., сам я просто не проверял, но ожидал этого.


    1. RomanPokrovskij
      20.12.2017 03:29

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


      1. vintage
        20.12.2017 09:24

        Аргументы простые:


        1. Каскадная загрузка зависимостей приводит к долгой загрузке всего, ибо пока браузер не загрузит зависимость, он не узнает какие у неё зависимости.
        2. Каскадная загрузка зависимостей приводит к визуальным артефактам во время первичной загрузки.
        3. Из-за тотальной изоляции крайне сложно кастомизировать компоненты извне.
        4. Вместо одного дом-дерева у вас много дом-деревьев и кривой апи, где половина ручек работает с локальным деревом, половина с глобальным. Не помню деталей, но там всё довольно кривосыро. Вроде были проблемы с получением шаблона при импорте компонента из компонента.


        1. RomanPokrovskij
          20.12.2017 12:54

          Спасибо. Может быть глупый вопрос: а чем тотальна изоляция polymer web component? Более чем react component?


          1. vintage
            20.12.2017 21:17

            Я сейчас говорил про нативные web-components. Полимер-то умеет "вулканизировать", собирая бандлы, что лишний раз показывает бестолковость изначальной идеи о пофайловой загрузке модулей. Это на сервере можно себе позволить ходить за модулями по требованию, ибо до файловой системы латентность крайне низка. Для фронта это не годится.


            1. Punk_UnDeaD Автор
              20.12.2017 21:23

              Вроде как подразумевается, что с http/2 всё становится волшебно.
              А ещё есть манифест. Но особенного смысла по сравнению с упаковкой я тоже не вижу.

              Только давайте отдельно про загрузку, а отдельно про изоляцию.


  1. Boyd_Rice
    19.12.2017 13:49

    Как-то с трудом представляю веб-компоненты в конвейере какого-либо популярного фреймворка, особенно Angular.
    PS: «Полимерная» версия Youtube работает отвратительно медленно что в Chrome, что в Edge, что в FF, что в Опере.


    1. Synoptic
      19.12.2017 19:06

      У меня прекрасно все работает.


      1. Boyd_Rice
        21.12.2017 12:29

        Что именно? Полимерный ютуб или веб-компоненты в Angular?


  1. unix_max
    19.12.2017 20:34

    Классная статья. Спасибо огромное. Давно искал решение для этой проблемы.