HTML Imports были частью ранней спецификации Web Components и предназначались для декларативного подключения HTML-документов в другие HTML-документы:
<link rel="import" href="my-component.html">
Импортируемый файл мог содержать разметку, стили и скрипты. Браузер
загружал его один раз и кэшировал, а содержимое становилось доступным
через document.imports. Основная идея заключалась в
модульности интерфейса на уровне HTML без явного управления
JavaScript-зависимостями.
Внутри импортируемого документа часто определялись кастомные элементы:
<template id="my-element">
<style>
:host { display: block; }
</style>
<div>Content</div>
</template>
<script>
class MyElement extends HTMLElement {
connectedCallback() {
const tpl = document.currentScript.ownerDocument
.getElementById('my-element');
this.attachShadow({ mode: 'open' })
.appendChild(tpl.content.cloneNode(true));
}
}
customElements.define('my-element', MyElement);
</script>
Такой подход выглядел логичным на фоне отсутствия стандартных модулей JavaScript и слабой поддержки сборщиков.
HTML Imports не стали частью финального веб-стандарта и были удалены из Chromium в 2020 году. Основные проблемы:
Спецификация Web Components была пересмотрена, и в качестве основы для модульности был выбран JavaScript, а не HTML.
Стандартные модули JavaScript полностью заменили HTML Imports.
Подключение компонентов происходит через import:
import './my-element.js';
Каждый модуль имеет собственную область видимости, поддерживает явные
зависимости и загружается браузером нативно. Это устранило необходимость
в специальных API вроде document.imports.
В Lit весь код компонентов строится вокруг ES Modules. Один компонент — один модуль:
import { LitElement, html, css } from 'lit';
export class MyElement extends LitElement {
static styles = css`
:host { display: block; }
`;
render() {
return html`<div>Content</div>`;
}
}
customElements.define('my-element', MyElement);
HTML Imports позволяли хранить шаблоны в
<template> внутри HTML. Lit использует
JavaScript-шаблоны на основе tagged template literals:
render() {
return html`
<section>
<h1>${this.title}</h1>
</section>
`;
}
Преимущества подхода:
Стили инкапсулируются через Shadow DOM и описываются в виде JavaScript-констант:
static styles = css`
h1 {
color: var(--primary-color);
}
`;
HTML Imports загружались декларативно через
<link>. Современный эквивалент — динамический
import():
if (condition) {
await import('./heavy-component.js');
}
В контексте Lit это используется для ленивой загрузки компонентов, маршрутизации и оптимизации размера бандла.
HTML Imports плохо сочетались со сборкой. Современный стек строится вокруг:
Эти инструменты понимают ES Modules, выполняют tree-shaking и код-сплиттинг. Lit проектируется с учетом работы без сборки, но при этом полностью совместим с ней.
Пример структуры проекта:
src/
components/
my-element.ts
other-element.ts
app.ts
index.html
<script type="module" src="/src/app.ts"></script>
HTML Imports создавали иллюзию глобального пространства компонентов. Lit и ES Modules требуют явного подключения:
import './components/my-element.js';
Это делает зависимости прозрачными и устраняет побочные эффекты загрузки.
Современная архитектура Lit опирается исключительно на стандарты:
HTML Imports были экспериментальной надстройкой. Их удаление упростило экосистему и сделало Web Components более предсказуемыми.
Типичные шаги миграции:
<template> в render()<style> в static stylesdocument.currentScript.ownerDocument на
модульную структуру<link rel="import"> в пользу
importПример преобразования:
Было (HTML Import):
<link rel="import" href="my-element.html">
Стало (Lit + ES Modules):
import './my-element.js';
Lit использует JavaScript как единый источник истины для логики, шаблонов и стилей. Это полностью устраняет необходимость в HTML Imports и решает те же задачи более строго, типобезопасно и масштабируемо.