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

Связанные темы

Ресурсы