Haunted — это легковесная библиотека для создания веб-компонентов на базе функциональных компонентов, вдохновлённая React Hooks. Одной из ключевых особенностей является гибкая система регистрации компонентов, которая позволяет создавать и подключать компоненты динамически, без необходимости заранее объявлять все элементы в HTML или в основном скрипте приложения.
В Haunted каждый компонент является функцией, которая возвращает
шаблон lit-html. Регистрация компонента выполняется через
функцию customElements.define, однако стандартный подход
предполагает статическую регистрацию. Динамическая регистрация позволяет
создавать компоненты в рантайме, что особенно полезно при модульной
архитектуре или ленивой загрузке частей интерфейса.
Ключевые моменты динамической регистрации:
Перед динамической регистрацией важно убедиться, что компонент с
таким тегом ещё не зарегистрирован, чтобы избежать ошибок
DOMException: Registration failed.
function defineComponent(tagName, component) {
if (!customElements.get(tagName)) {
customElements.define(tagName, component);
}
}
Функция customElements.get(tagName) возвращает
конструктор зарегистрированного элемента или undefined,
если элемент ещё не зарегистрирован.
Динамическая регистрация часто применяется вместе с ленивой загрузкой:
async function loadComponent(tagName, path) {
if (!customElements.get(tagName)) {
const module = await import(path);
customElements.define(tagName, module.default);
}
}
В этом примере компонент загружается только при первом обращении, а
module.default — это функциональный компонент Haunted,
экспортированный из модуля.
import { html, component } from 'haunted';
function Counter({ initial = 0 }) {
const [count, setCount] = useState(initial);
return html`
<div>
<p>Счёт: ${count}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
defineComponent('my-counter', component(Counter));
При динамической регистрации этот же компонент можно подключать через
функцию loadComponent, что позволяет отложить загрузку:
await loadComponent('my-counter', './counter.js');
document.body.innerHTML = `<my-counter></my-counter>`;
В SPA-приложениях динамическая регистрация позволяет загружать компоненты по маршруту:
const routes = {
'/dashboard': () => loadComponent('dashboard-view', './views/dashboard.js'),
'/settings': () => loadComponent('settings-view', './views/settings.js'),
};
window.addEventListener('popstate', async () => {
const route = routes[window.location.pathname];
if (route) await route();
});
Такой подход сокращает время первичной загрузки и поддерживает модульность проекта.
Haunted компоненты часто используют хуки для состояния
(useState, useEffect). Динамическая
регистрация не влияет на работу этих хуков, но важно правильно
передавать параметры:
await loadComponent('user-card', './components/user-card.js');
const card = document.createElement('user-card');
card.setAttribute('user-id', '42');
document.body.appendChild(card);
Внутри компонента user-card можно использовать
useEffect для загрузки данных по атрибуту
user-id.
import() возвращают уже загруженный модуль, что снижает
нагрузку.defineOnce, которая предотвращает дублирование
регистрации.useEffect с
асинхронными вызовами для инициализации данных.ES Modules.custom-elements-es5-adapter.component) от Haunted
остаётся неизменным при динамической регистрации.customElements.get.import() для
ленивой загрузки компонентов.Динамическая регистрация делает Haunted особенно гибким инструментом для построения масштабируемых и модульных веб-приложений, где каждый компонент загружается и инициализируется только по мере необходимости.