Islands Architecture
Islands Architecture — архитектурный паттерн, при котором страница рендерится как статический HTML с "островами" интерактивности — изолированными React/Preact/Vue компонентами, которые гидрируются независимо, минимизируя объём JavaScript.
Зачем нужно
Традиционный SSR с полной гидрацией отправляет JavaScript для всей страницы. Islands Architecture гидрирует только интерактивные части (корзина, поиск, меню) — остальной контент остаётся чистым HTML. Результат: Time to Interactive (TTI) и INP значительно лучше.
Где используется
- Content-heavy сайты: блоги, маркетинг, документация (90% статики, 10% интерактивности)
- E-commerce: статические карточки товаров + интерактивная корзина/фильтры
- Фреймворки: Astro, Fresh (Deno), Marko, Qwik
Основной контент
Концепция "острова"
┌─────────────────────────────────────┐
│ Статический HTML (без JS) │
│ │
│ ┌──────────────┐ │
│ │ 🏝 Island │ ← Интерактивный │
│ │ SearchBar │ компонент │
│ │ (React) │ с гидрацией │
│ └──────────────┘ │
│ │
│ <article>Статья...</article> │
│ │
│ ┌──────────────┐ │
│ │ 🏝 Island │ │
│ │ CartButton │ │
│ │ (Preact) │ │
│ └──────────────┘ │
└─────────────────────────────────────┘
Astro — Islands Architecture фреймворк
---
// src/pages/product.astro
import ProductCard from '../components/ProductCard.astro'; // Нет JS
import CartButton from '../components/CartButton.jsx'; // React island
import SearchBar from '../components/SearchBar.svelte'; // Svelte island
---
<html>
<body>
<!-- Статический контент — ноль JavaScript -->
<ProductCard name="iPhone 15" price={999} />
<!-- Islands с различными стратегиями гидрации -->
<SearchBar client:load /> <!-- Гидрация сразу -->
<CartButton client:visible /> <!-- Гидрация при появлении в viewport -->
<Newsletter client:idle /> <!-- Гидрация в idle time -->
<Modal client:media="(max-width: 640px)" /> <!-- Только на mobile -->
</body>
</html>
Директивы гидрации в Astro
client:load — гидрировать немедленно (для критичных компонентов)
client:visible — гидрировать при попадании в viewport (IntersectionObserver)
client:idle — гидрировать в requestIdleCallback (некритичные)
client:media — гидрировать при совпадении media query
client:only — только CSR, без SSR HTML (iframe, canvas)
Ручная реализация island pattern (React)
// Lazy island — компонент загружается только при необходимости
import { lazy, Suspense, useState, useEffect } from 'react';
const HeavyChart = lazy( => import('./HeavyChart'));
function ChartIsland({ data }) {
const [isVisible, setIsVisible] = useState(false);
const ref = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
});
observer.observe(ref.current);
return => observer.disconnect();
}, );
return (
<div ref={ref}>
{isVisible ? (
<Suspense fallback={<div>Loading chart...</div>}>
<HeavyChart data={data} />
</Suspense>
) : (
<div style={{ height: 400 }}>Chart placeholder</div>
)}
</div>
);
}
Частые ошибки
- Делать "остров" из статического контента — теряется весь смысл паттерна
client:loadдля всех компонентов — то же самое, что обычный SSR- Слишком крупные острова — включают компоненты, которые не нужны сразу
- Отсутствие Suspense fallback для ленивых компонентов — FOIT для UI
Связанные темы
- _MOC Производительность
- SSR vs CSR -- производительность
- React -- Suspense и lazy
- Метрики -- FCP, TTFB, TTI, TBT