Ленивая загрузка в контексте библиотек для веб-компонентов — это стратегия оптимизации, позволяющая загружать и инициализировать компоненты только тогда, когда они действительно нужны. В Haunted, библиотеке для создания реактивных веб-компонентов на основе Hooks, ленивые компоненты реализуются через динамический импорт и использование асинхронных хуков. Это позволяет уменьшить первоначальный вес страницы и ускорить время первой отрисовки.
В Haunted компонент — это функция, которая возвращает шаблон с
помощью html. Для ленивой загрузки можно использовать
стандартный синтаксис динамического импорта:
import { component, html } from 'haunted';
const LazyComponent = async () => {
const module = await import('./MyComponent.js');
return module.MyComponent;
};
Особенности:
MyComponent.js не включается в основной бандл, а
загружается при необходимости.LazyComponent сам по себе является функцией,
возвращающей промис с компонентом.Haunted предоставляет стандартный набор хуков (useState,
useEffect), с помощью которых можно управлять состоянием
загрузки. Пример организации ленивого компонента с индикатором
загрузки:
import { html, component, useState, useEffect } from 'haunted';
function AsyncWrapper({ loader }) {
const [LoadedComponent, setLoadedComponent] = useState(null);
useEffect(() => {
let isMounted = true;
loader().then((module) => {
if (isMounted) {
setLoadedComponent(() => module.default || module);
}
});
return () => { isMounted = false; };
}, [loader]);
return LoadedComponent
? html`<${LoadedComponent}></${LoadedComponent}>`
: html`<p>Загрузка...</p>`;
}
customElements.define('async-wrapper', component(AsyncWrapper));
Пояснение:
loader — функция, возвращающая промис динамического
импорта.useState хранит загруженный компонент после разрешения
промиса.useEffect гарантирует, что загрузка произойдет только
при монтировании компонента, а также предотвращает утечки памяти при
размонтировании.<p>Загрузка...</p> может быть
заменен на любой индикатор прогресса.Для компонентов, которые активно используются в интерфейсе, полезно комбинировать ленивую загрузку с условным рендерингом:
import { html, component, useState } from 'haunted';
function Dashboard() {
const [showSettings, setShowSettings] = useState(false);
return html`
<button @click=${() => setShowSettings(true)}>Открыть настройки</button>
${showSettings
? html`<async-wrapper .loader=${() => import('./Settings.js')}></async-wrapper>`
: ''}
`;
}
customElements.define('dashboard-view', component(Dashboard));
Особенности такого подхода:
async-wrapper обеспечивает корректный рендер во время
асинхронной загрузки.Асинхронные компоненты могут завершаться с ошибкой, поэтому важно предусматривать обработку исключений:
useEffect(() => {
let isMounted = true;
loader()
.then((module) => {
if (isMounted) setLoadedComponent(() => module.default || module);
})
.catch((error) => {
console.error('Ошибка при загрузке компонента:', error);
if (isMounted) setLoadedComponent(() => () => html`<p>Не удалось загрузить компонент</p>`);
});
return () => { isMounted = false; };
}, [loader]);
Рекомендации:
<link rel="preload"> или динамический импорт с
таймаутом.Suspense, можно реализовать
аналог, используя useState и условный рендеринг, как
показано в примере с AsyncWrapper.import { html, component, useState, useEffect } from 'haunted';
function LazyTabs() {
const [activeTab, setActiveTab] = useState('home');
const [TabComponent, setTabComponent] = useState(null);
useEffect(() => {
let isMounted = true;
const loader = {
home: () => import('./HomeTab.js'),
profile: () => import('./ProfileTab.js'),
settings: () => import('./SettingsTab.js'),
}[activeTab];
loader()
.then((mod) => { if (isMounted) setTabComponent(() => mod.default); })
.catch((err) => { console.error(err); });
return () => { isMounted = false; };
}, [activeTab]);
return html`
<nav>
<button @click=${() => setActiveTab('home')}>Home</button>
<button @click=${() => setActiveTab('profile')}>Profile</button>
<button @click=${() => setActiveTab('settings')}>Settings</button>
</nav>
${TabComponent ? html`<${TabComponent}></${TabComponent}>` : html`<p>Загрузка вкладки...</p>`}
`;
}
customElements.define('lazy-tabs', component(LazyTabs));
Особенности реализации:
activeTab для управления
текущим активным компонентом.Эти методы обеспечивают гибкую, эффективную и безопасную реализацию ленивой загрузки в Haunted, позволяя создавать легкие и отзывчивые веб-приложения.