Введение в HTML импорты

Template, Shadow DOM, и Custom Elements позволяют вам строить UI компоненты проще и быстрее. Однако, это не самый эффективный способ загрузки ресурсов HTML, CSS и JavaScript по отдельности.

Для загрузки библиотек типа jQuery UI или Bootstrap требуются отдельные тэги для JavaScript, CSS, и Web шрифтов. Все становится проще при использовании Web Components с несколькими зависимостями.

HTML импорты позволяют загружать ресурсы как совокупность нескольких файлов этого типа.

Предлагаю вам ознакомиться с видео по данной теме.

Использование HTML импортов

Чтобы загрузить HTML файл, добавьте тэг link с import’ом в параметре rel и href, содержащий путь до нужного файла. К примеру, если вы хотите загрузить файл под названием component.html в index.html, то все должно выглядеть так:
index.html

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

Вы можете загружать любые ресурсы, включая скрипты, таблицы стилей и шрифты:
component.html

<link rel="stylesheet" href="css/style.css">
<script src="js/script.js"></script>

doctype, html, head, body необязательны. HTML импорты автомагически загрузят все указанные элементы, добавят их на страницу и запустят JavaScript, если имеется.

Порядок исполнения

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

Во избежание блокировки тэгом script оставшегося HTML можно использовать атрибуты async / defer (также можно переместить все скрипты в конец страницы). defer указывает на то, что код можно запустить лишь после загрузки HTML. async позволяет браузеру выполнять эти два действия параллельно.

Итак, как же работают импорты?

Скрипт внутри HTML импорта работает как обычный тэгscript с атрибутом defer. В примере ниже index.html запустит script1.js иscript2.js внутри component.html перед исполнением script3.js.
index.html

<link rel="import" href="component.html"> // 1.
<title>Пример импорта</title>
<script src="script3.js"></script>        // 4.

component.html

<script src="js/script1.js"></script>     // 2.
<script src="js/script2.js"></script>     // 3.
  1. Загружается component.html из index.html и ожидает исполнения;
  2. Загружается script1.js в component.html;
  3. Загружается script2.js в component.html после script1.js;
  4. Загружается script3.js в index.html после script2.js.

Заметьте, что добавление атрибута async в link[rel=»import»] расценивается как атрибут async в тэге script. Он не будет блокировать HTML. Это может потенциально улучшить производительность вашего проекта.

За рамками происходящего

На самом деле, HTML импорты не могут перенести полностью файл с другого источника. К примеру, вы не можете импортировать вhttp://example.com/ страницу http://webcomponents.org/.

Чтобы избежать этого ограничения, используйте CORS (Cross Origin Resource Sharing). Чтобы узнать больше об этой технологии, прочтите эту статью.

Объекты window и document в импортируемых файлах

Ранее я упоминал то, что импортируемые JavaScript будут запущены на странице. К сожалению, такое нельзя сказать об импортируемых HTML файлах. Чтобы такое происходило и с ними, надо дописать немножко скриптов.

Остерегайтесь того, что объект document в импортируемом файле будет ссылаться на страницу оригинала.

Используя написанный ранее код в качестве примера, заставим document в index.html и component.html ссылаться на document вindex.html.

Внесем небольшие изменения в наши файлы.
index.html

var link = document.querySelector('link[rel="import"]');
link.addEventListener('load', function(e) {
  var importedDoc = link.import;
  // importedDoc points to the document under component.html
});

Для получения document из component.html дополните ваш код с document.currentScript.ownerDocument.
component.html

var mainDoc = document.currentScript.ownerDocument;
// mainDoc points to the document under component.html

Если вы используете webcomponents.js, воспользуйтесь document._currentScript вместо document.currentScript. Нижнее подчеркивание в currentScript используется для поддержания браузеров, не способных работать с этим компонентом без использования сего знака.
component.html

var mainDoc = document._currentScript.ownerDocument;
// mainDoc points to the document under component.html

Написав вот это в начале вашего скрипта, можно легко получить доступ к document из component.html, даже если браузер не поддерживает HTML импорты.

document._currentScript = document._currentScript || document.currentScript;

Вопросы производительности

Один из плюсов использования импортов — возможность самостоятельно распределить нагрузку страницы и порядок обработки импортируемых объектов. Но это еще и означает, что HTML код увеличится. Вообще, есть несколько пунктов для сравнения:

Зависимости

Что делать, если несколько вставляемых документов ссылаются на одну и ту же библиотеку? Например:

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

<link rel="import" href="component1.html">
<link rel="import" href="component2.html">

component1.html

<script src="js/jquery.js"></script>

component2.html

<script src="js/jquery.js"></script>

Данная проблема крайне легко решается в импортах.

В отличие от тэга script, объекты нашей статьи не загружают повторно один и тот же материал. Смотря на последний пример, достаточно обернуть тэг script HTML импортом, и данный ресурс не будет загружен дважды.
fa67d091d72a442f8910ab67fa27a68b
Но есть и другая проблема: теперь файлов для загрузки стало больше. Что делать, если таких будет не два, а гораздо больше?

К счастью, нам на помощь идет инструмент под названием «Vulcanize».

Объединение сетевых запросов

Vulcanize — инструмент объединения нескольких HTML файлов в один, с помощью чего число подключений к сети в целях загрузки необходимых документов сокращается. Вы можете установить его с помощью npm и использовать в командной строке. Также существуют аналоги для grunt и gulp, с помощью чего можно сделать «Vulcanize» частью вашего процесса сборки.

Для объединения файлов index.html используем следующий код:

$ vulcanize -o vulcanized.html index.html

При исполнении данной команды все зависимости index.html будут соединены в файле vulcanized.html.

Прочитать больше о данном инструменте можно здесь.

Сочетание импортов с Template, Shadow DOM и Custom Elements

Давайте использовать HTML ipmport вместе с другими интересными инструментами, рассмотренными ранее.

Для тех, кто не знает о данных технологиях: С templates определение содержания пользовательского элемента может быть декларативным. С Shadow DOM styles, ID и classes элемента можно использовать немного иначе. С Custom Elements можно создать собственные HTML тэги. Неплохо, не так ли?

Объединение импортов с собственными веб-компонентами получит модульность и возможность многократного использования. Любой сможет их использовать, добавив лишь тэг link.
x-component.html

<template id="template">
  <style>
    ...
  </style>
  <div id="container">
    <img class="webcomponents" src="http://webcomponents.org/img/logo.svg">
    <content select="h1"></content>
  </div>
</template>
<script>
  // This element will be registered to index.html
  // Because `document` here means the one in index.html
  var XComponent = document.registerElement('x-component', {
    prototype: Object.create(HTMLElement.prototype, {
      createdCallback: {
        value: function() {
          var root = this.createShadowRoot();
          var template = document.querySelector('#template');
          var clone = document.importNode(template.content, true);
          root.appendChild(clone);
        }
      }
    })
  });
</script>

index.html

 ...
  <link rel="import" href="x-component.html">
</head>
<body>
  <x-component>
    <h1>This is Custom Element</h1>
  </x-component>
  ...

Обратите внимание, что объект document в x-component.html такой же, как и в index.html. Не нужно писать ничего сложного, все работает само и за вас.

Поддерживаемые браузеры

HTML импорты поддерживаются браузерами Chrome и Opera. Firefox на данный момент отложил добавление данной фичи, так как «у них есть более приоритетные задачи».

Чтобы проверить данный метод на совместимость с конкретным браузером, посетите chromestatus.com или caniuse.com. Для добавления возможности работы этой технологии в других браузерах, воспользуйтесь webcomponents.js (ранее platform.js).

Ресурсы

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