Синтаксис и зависимости

Библиотека Haunted представляет собой тонкий слой над Web Components, позволяющий использовать реактивные хуки из экосистемы React для построения компонент без громоздкой инфраструктуры. Синтаксис следует идеям функционального программирования: функция описывает рендер, состояние управляется хуками, а компонент объявляется однократно и затем используется в разметке как нативный элемент.

Haunted использует функцию component для обёртывания рендера и регистрации Web Component:

import { component, useState } from 'haunted';

function Counter() {
  const [count, setCount] = useState(0);
  return html`
    <button @click=${() => setCount(count + 1)}>${count}</button>
  `;
}

customElements.define('my-counter', component(Counter));

Ключевые особенности синтаксиса:

• Рендер представлен функцией без класса. • Внутри возможны хуки useState, useEffect, useMemo и другие. • Возврат осуществляется шаблонной строкой html, предоставляемой библиотекой lit-html. • Регистрация в customElements.define делает компонент доступным как HTML-элемент.

Зависимости

Haunted не рендерит HTML напрямую. Для шаблонов требуется lit-html или его наследник lit. Из коробки используется lit-html, поэтому важно убедиться в наличии соответствующего пакета:

npm install haunted lit-html

При использовании актуальной линейки Lit зависимость меняется следующим образом:

npm install haunted lit

Импорт шаблонов в актуальной версии Lit:

import { html } from 'lit';

В старой версии:

import { html } from 'lit-html';

Внешние стили не навязываются: стилизация может выполняться через Shadow DOM, global CSS или CSS-in-JS. Haunted лишь создаёт реактивный рендер-функциональный слой, не вмешиваясь в выбор стека.

Механика хуков

Хуки в Haunted полностью вдохновлены архитектурой React, при этом синтаксис идентичен большинству случаев:

import { useState, useEffect } from 'haunted';

useState хранит локальное состояние компонента, useEffect выполняет побочные действия с опциональной очисткой, useMemo и useCallback оптимизируют вычисления. Основополагающее правило: количество и порядок хуков в функции должны оставаться стабильными, иначе внутренний менеджер состояния нарушит соответствие индексов.

Пример использования эффектов:

function Timer() {
  const [t, setT] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setT(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);

  return html`${t}`;
}

Фабрика component

Функция component связывает рендер-функцию с жизненным циклом Web Components: создаёт Shadow DOM (по умолчанию), подключает автообновление при изменении состояния и обеспечивает корректную очистку эффектов при удалении узла из DOM.

Допустимые аргументы фабрики:

component(render, { useShadowDOM: true })

Опция useShadowDOM отключается при необходимости взаимодействия с глобальными стилями или фреймворками, рендерящими в Light DOM.

Атрибуты и свойства

Web Components ожидают передачи данных либо атрибутами, либо через JS-свойства. Haunted принимает оба варианта. При использовании атрибутов значения сериализуются в строки, поэтому для сложных данных предпочтительнее свойства:

el.items = [{ id: 1 }, { id: 2 }];

Чтобы синхронизировать атрибуты и свойства, можно добавить observedAttributes через сторонние паттерны или вспомогательные утилиты. Haunted здесь не вводит дополнительной магии, сохраняя контроль на уровне платформы.

Зависимости окружения

Haunted не требует сборщика, но чаще применяется в связке с Rollup, Vite или Webpack. Это упрощает использование современных импортов и tree shaking. Корректный таргет — современные браузеры с поддержкой Custom Elements, Shadow DOM и ES Modules. Для старых браузеров требуется набор полифилов:

• Custom Elements • Shadow DOM • ES Modules или SystemJS

Полифилы не включены в библиотеку намеренно, чтобы не увеличивать размер бандла и оставить выбор разработчику.

Взаимодействие с экосистемой

Haunted органично работает с любым инструментом, который понимает Web Components: • Lit (для шаблонов и директив) • Storybook (для документации) • Design Systems (как часть UI-библиотек) • Фреймворки, поддерживающие внешние Web Components (Vue, Svelte, Angular)

Отсутствие собственного DOM-диффа и логики синхронизации делает Haunted минималистичной прослойкой, обеспечивающей реактивное состояние и жизненный цикл поверх нативной платформы.