Przejdź do treści

Architektura wysp i selektywna hydratacja w frameworku Astro

Zobacz, jak Astro dzieli HTML, Client Islands i Server Islands. Dobierz client:load, idle i visible bez opóźniania interakcji i wysyłania zbędnego JS.

Maciej Sala

Founder StriveLab

11 min czytaniaAktualizacja

Architektura wysp to wzorzec rozdzielający dokument HTML od niezależnych obszarów interaktywnych. Astro wymaga jawnego włączenia hydratacji, co utrudnia przypadkowe wysłanie całego drzewa frameworka do klienta. Nadal trzeba jednak optymalizować obrazy, fonty, CSS, skrypty zewnętrzne, cache i kod samych wysp.

Skąd wzięła się Islands Architecture?

Pojęcie zostało ukute w 2019 roku przez Katie Sylor-Miller, architektkę frontendu Etsy, a później rozwinięte przez Jasona Millera, twórcę Preacta, w jego artykule z 2020 roku. Idea jest pozornie prosta: renderuj stronę jako HTML na serwerze, a w obszarach, które faktycznie potrzebują interaktywności, umieść niezależne komponenty hydratowane osobno.

W klasycznym cała aplikacja bywa jednym drzewem klienckim. Przeglądarka pobiera jego JavaScript, uruchamia framework i dopiero wtedy może obsłużyć interakcje. SSR potrafi wcześniej pokazać HTML, ale nie usuwa kosztu hydratacji klienta. Gdy kod dotrze za późno, widoczny przycisk może jeszcze nie reagować.

Nie należy przenosić tego opisu jeden do jednego na każdy współczesny metaframework. W Next.js App Router layouty i strony są domyślnie Server Components, a JavaScript hydratuje Client Components wyznaczone granicą 'use client'. Next przesyła również payload RSC i obsługuje nawigację po stronie klienta. Astro wybiera inny model: dokument może pozostać klasyczną stroną MPA, a każdy komponent frameworka dostaje klienta dopiero po dodaniu dyrektywy client:*.

Islands Architecture odwraca ten model — strona jest domyślnie statycznym HTML-em, a interaktywność to wyjątek, który aktywnie deklarujesz.

Jak Islands Architecture działa w Astro?

Weźmy typową stronę firmową z nagłówkiem, hero, sekcją usług, formularzem i stopką. W klienckim SPA wszystkie elementy mogą znaleźć się w jednym hydratowanym drzewie. Next.js App Router pozwala ograniczyć klienta granicami Client Components. W Astro punktem wyjścia są komponenty renderowane do HTML, a formularz może stać się osobną wyspą.

W Astro piszesz to tak:

Code
---
// src/pages/index.astro
import Header from '../components/Header.astro';
import Hero from '../components/Hero.astro';
import Services from '../components/Services.astro';
import ContactForm from '../components/ContactForm.tsx';
import Footer from '../components/Footer.astro';
---
 
<Header />
<Hero />
<Services />
<ContactForm client:visible />
<Footer />

Header, Hero, Services i Footer to komponenty .astrorenderują się do HTML-u podczas builda lub na żądanie. Kod z frontmatteru nie trafia do klienta, choć jawny <script> w komponencie nadal trafi. ContactForm jest komponentem React z client:visible, więc jego kod zostanie pobrany i zhydratowany, gdy obszar wejdzie w viewport.

HTML formularza może być widoczny wcześniej dzięki renderowaniu serwerowemu, ale obsługa React zacznie działać dopiero po hydratacji. Dlatego komponent powinien mieć natywne zachowanie zastępcze albo zostać zhydratowany odpowiednio wcześnie. client:visible={{ rootMargin: '200px' }} może rozpocząć pracę przed wejściem sekcji na ekran.

Zero JS domyślnie w Astro: co to naprawdę znaczy?

W Astro komponent frameworka bez client:* jest renderowany do HTML-u bez wysłania jego kodu klienckiego. Strona może więc mieć 0 KB własnego JavaScriptu, o ile nie zawiera skryptów, routera przejść, wysp klienckich ani integracji dodających kod w przeglądarce. To właściwość wyniku builda, którą warto potwierdzić w panelu Network, a nie gwarancja dla każdego projektu Astro.

Code
<!-- To jest cały HTML, który dostaje przeglądarka dla strony bez islands -->
<!doctype html>
<html lang="pl">
  <head>
    <meta charset="UTF-8" />
    <title>Strona główna</title>
    <link rel="stylesheet" href="/_astro/about.abc123.css" />
  </head>
  <body>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  </body>
</html>

Brak runtime'u ogranicza parsowanie i wykonywanie JavaScriptu, co może pomóc responsywności oraz . Nie gwarantuje jednak wyniku Lighthouse ani zaliczenia : może zepsuć ciężki obraz lub wolny serwer, CLS — fonty i reklamy, a INP — kod zewnętrznego widżetu. Wydajność oceniaj na danych terenowych i reprezentatywnych podstronach.

Dyrektywy hydratacji w Astro jako kontrakt wydajności

Kiedy komponent frameworka musi być interaktywny, Astro pozwala określić, kiedy zacznie pobierać i hydratować JavaScript. Dyrektywa jest dostępna dla komponentu UI bezpośrednio importowanego do pliku .astro, a jej wybór powinien wynikać z najwcześniejszej możliwej interakcji:

  • client:load — ładuje i hydratuje komponent możliwie szybko. Dla UI, którego użytkownik może potrzebować natychmiast, niezależnie od położenia na stronie.
  • client:idle — czeka na , a przy braku jego obsługi na zdarzenie load. Opcja timeout pozwala ograniczyć maksymalne opóźnienie.
  • client:visible — używa . Opcjonalny rootMargin rozpoczyna hydratację przed faktycznym wejściem komponentu w viewport.
  • client:media="(max-width: 50em)" — hydratuje, kiedy media query pasuje. Dla UI przeznaczonego wyłącznie na określony wariant ekranu.
  • client:only="react" — pomija , dlatego Astro wymaga wskazania frameworka, np. react lub vue. Używaj tylko wtedy, gdy komponentu nie da się wyrenderować na serwerze; treść nie znajdzie się w początkowym HTML-u.

Opóźniona hydratacja może poprawić początkowe ładowanie, ale nie może tworzyć martwego interfejsu. Testuj szybkie przewijanie i kliknięcie przed hydratacją na wolnym połączeniu oraz słabszym telefonie. Dla linków i formularzy preferuj natywne HTML jako działający fundament, a JavaScript traktuj jako ulepszenie.

Szczegółowo rozbieram każdą z nich w artykule o client directives w Astro.

Hydratacja musi odtworzyć ten sam interfejs

Komponent frameworka jest najpierw renderowany do HTML-u, a następnie uruchamiany ponownie w przeglądarce. Początkowy wynik obu środowisk powinien być zgodny. Losowa wartość, bieżąca data, szerokość okna lub dane z localStorage użyte bez zabezpieczenia mogą wywołać hydration mismatch albo nagłą zmianę treści.

Przekazuj do wyspy możliwie małe, serializowalne propsy. Dane zależne od przeglądarki odczytuj po uruchomieniu komponentu, ale zaprojektuj stabilny stan początkowy. client:only usuwa problem zgodności przez rezygnację z SSR, lecz ceną jest brak właściwej treści w początkowym HTML-u — nie powinien być automatycznym rozwiązaniem każdego ostrzeżenia.

Komponenty z różnych frameworków na jednej stronie Astro

Architektura wysp ma jeszcze jedną konsekwencję, która w praktyce okazuje się bardziej użyteczna, niż się wydaje na pierwszy rzut oka — każda wyspa jest niezależna, więc może być napisana w innym frameworku.

Code
---
import ReactCounter from '../components/ReactCounter.tsx';
import VueChart from '../components/VueChart.vue';
import SvelteForm from '../components/SvelteForm.svelte';
---
 
<ReactCounter client:load />
<VueChart client:visible />
<SvelteForm client:idle />

W tradycyjnej SPA takie połączenie byłoby trudne do utrzymania, bo framework jest zwykle jeden. W Astro każda wyspa może używać własnego frameworka, ale nie oznacza to darmowego mieszania technologii. React, Vue i Svelte wnoszą oddzielne runtime'y, integracje, konwencje testowania i zależności. Bundler może współdzielić chunki między wyspami tego samego frameworka, więc nie każda wyspa jest osobną, całkowicie zduplikowaną paczką.

Mieszanie frameworków ma sens przede wszystkim podczas stopniowej migracji albo przy ponownym wykorzystaniu trudnego do zastąpienia komponentu. W nowym projekcie jeden framework kliencki zwykle upraszcza zależności, dostępność, testy i współdzielenie stanu. Zanim dodasz kolejny runtime, porównaj koszt integracji z kosztem przepisania komponentu.

Server Islands i dynamiczne fragmenty statycznej strony

Server Islands rozwiązują inny problem niż selektywna hydratacja. Komponent z server:defer nie renderuje się razem z główną stroną; przeglądarka otrzymuje fallback, a następnie mały skrypt pobiera osobno HTML wygenerowany na serwerze. Mechanizm pojawił się eksperymentalnie w Astro 4.12, ale w aktualnym projekcie kieruj się dokumentacją używanej wersji, a nie historycznym numerem wydania.

Code
---
// src/pages/product.astro
import ProductDetails from '../components/ProductDetails.astro';
import LiveInventory from '../components/LiveInventory.astro';
---
 
<ProductDetails />
 
<!-- Server Island - renderuje się osobno, nie blokuje głównej odpowiedzi -->
<LiveInventory server:defer>
  <div slot="fallback">Ładowanie stanu magazynu...</div>
</LiveInventory>

Główna strona może być prerenderowana lub renderowana na żądanie, a dynamiczny fragment — np. stan magazynu albo spersonalizowany avatar — dociera osobnym żądaniem. Komponent serwerowy nie wymaga runtime'u frameworka do hydratacji, ale Server Island nie oznacza zerowego kosztu: dochodzi endpoint, round trip, skrypt podmiany, fallback oraz obsługa błędu. Cache i personalizację konfigurujesz zgodnie z danymi; odpowiedzi zależnej od cookies nie wolno przypadkowo udostępnić innym użytkownikom.

Server Islands wymagają adaptera obsługującego renderowanie na żądanie. Testuj je na docelowym hostingu, zwłaszcza pod kątem cookies, nagłówków cache, opóźnienia regionu, timeoutów i działania fallbacku bez odpowiedzi endpointu.

Szerzej opisuję ten mechanizm w artykule o Server Islands w Astro.

Kiedy Islands Architecture daje realne korzyści?

Architektura wysp pomaga przede wszystkim wtedy, gdy struktura produktu odpowiada granicom niezależnej interaktywności:

  1. Strona jest głównie treścią. Blog, dokumentacja, strona firmowa, portfolio lub landing page składają się przede wszystkim z tekstu, obrazów, linków i formularzy, które mogą działać bez rozbudowanego stanu klienta.
  2. Interaktywność ma wyraźne granice. Kalkulator, wyszukiwarka, menu i karuzela mogą działać niezależnie, bez wspólnego drzewa obejmującego cały layout.
  3. Koszt JavaScriptu jest realnym problemem. Profilowanie pokazuje długie zadania, wysokie użycie CPU albo opóźnione INP powodowane kodem aplikacji, a nie wyłącznie obrazami, serwerem czy zewnętrznymi skryptami.
  4. Zespół akceptuje model MPA. Nawigacja dokumentowa, URL jako źródło stanu i progresywne ulepszanie pasują do produktu oraz oczekiwanego UX.

Kiedy Islands Architecture nie pomaga?

I druga strona medalu:

  1. Większość ekranu tworzy jeden stanowy workflow. Edytor, rozbudowany dashboard lub narzędzie projektowe może być prostsze jako jedna większa aplikacja niż kilkanaście sztucznie rozdzielonych korzeni.
  2. Komponenty stale wymieniają stan. Wyspy potrafią komunikować się przez store lub serwer, ale duża liczba dwukierunkowych zależności jest sygnałem, że granice zostały postawione w niewłaściwym miejscu.
  3. Produkt zakłada intensywną nawigację kliencką i jeden ekosystem React. Next.js może lepiej pasować do zespołu korzystającego z RSC, Client Components i bibliotek wymagających wspólnego drzewa. Nie dlatego, że Astro nie ma backendu: Astro oferuje endpointy, middleware, Actions i renderowanie na żądanie. Różnią się dojrzałość integracji, model wdrożenia i ergonomia konkretnego przypadku.
  4. Główne koszty leżą poza kodem frameworka. Jeżeli wydajność ograniczają reklamy, tag manager, fonty, obrazy lub wolne API, samo rozbicie komponentów na wyspy nie usunie problemu.

Porównanie obu podejść szerzej opisałem w artykule Astro.js vs Next.js — które narzędzie wybrać w 2026 roku?.

Praktyczne wskazówki dla projektowania wysp w Astro

Jeśli zaczynasz projekt w Astro, rekomenduję następujący sposób myślenia:

Zaczynaj od działającego HTML-u. Nawigacja, link, formularz i element <details> często zapewniają podstawową funkcję bez frameworka. Po React, Vue lub Svelte z hydratacją sięgaj wtedy, gdy potrzebujesz stanu, złożonych zdarzeń albo biblioteki UI. Mały <script> w komponencie Astro może być prostszy niż cały runtime frameworka.

Wybieraj dyrektywę według interakcji. Nie przyjmuj client:visible jako automatycznego wyboru. Menu widoczne od początku może wymagać client:load, ciężka karuzela niżej — client:visible z rootMargin, a widget bez pilnej interakcji — client:idle z limitem czasu. CTA będące zwykłym linkiem nie wymaga hydratacji.

Nie zawijaj całego layoutu w React. To typowy błąd przy migracji z Next.js — programista przyzwyczajony do _app.tsx opakowuje wszystko w jeden komponent React. W Astro layout powinien być .astro, a Reacta używasz tylko w miejscach, które naprawdę potrzebują interakcji.

Nie twórz wyspy dla każdego wiersza bez pomiaru. Sto niezależnych korzeni ma koszt uruchamiania i zarządzania, nawet gdy bundler współdzieli runtime. Jeśli elementy wspólnie filtrują się lub sortują, jeden kontener może być prostszy. Gdy są niezależne i rzadko widoczne, kilka mniejszych granic może opóźnić niepotrzebny kod — decyzję potwierdź profilem.

Projektuj jawny przepływ stanu. React Context działa w obrębie jednej wyspy React, nie między osobnymi korzeniami. Do prostego stanu między wyspami możesz użyć , URL-a lub zdarzeń DOM. Danych biznesowych nie duplikuj bez kontroli w kilku klientach — ustal źródło prawdy i sposób synchronizacji z serwerem.

Testuj moment przed hydratacją. Wyłącz JavaScript, włącz wolne łącze i throttling CPU, a następnie kliknij element natychmiast po jego pojawieniu się. Sprawdź focus, klawiaturę, komunikaty formularza, stabilność layoutu i to, czy fallback nie wygląda jak aktywny przycisk, gdy jeszcze nim nie jest.

Budżet JavaScriptu dla wysp Astro

Dyrektywa client:* jest decyzją o budżecie i czasie interaktywności. Wyspa wnosi kod komponentu oraz zależności, ale bundler może wydzielić współdzielone chunki, więc nie licz kosztu przez proste mnożenie liczby wysp. Sprawdź początkowy JavaScript, kod pobrany po scrollu, coverage, długie zadania i INP. Porównaj zimne wejście z nawigacją wewnętrzną oraz urządzenie klasy średniej zamiast wyłącznie szybkiego laptopa.

Typ sekcjiDomyślna decyzjaDlaczego
Hero z tekstem i obrazem.astro, bez hydratacjiTreść i układ nie potrzebują JS
Formularz kontaktowyHTML + Astro Action; JS opcjonalnieMoże działać bez hydratacji, a JS ulepsza walidację
Menu mobilneMały skrypt lub wyspa z client:loadNawigacja musi działać od pierwszej interakcji
Kalkulator cenyclient:visible z rootMarginPowinien być gotowy, zanim użytkownik do niego dotrze
Opinie, logo, FAQStatyczny HTMLInteraktywność zwykle nie wnosi wartości

Islands Architecture a SEO

Z perspektywy SEO architektura wysp ułatwia umieszczenie kluczowej treści, linków i metadanych w początkowym HTML-u. Google potrafi renderować JavaScript, ale ważna treść nie powinna zależeć wyłącznie od hydratacji wyspy. client:only zastosowany do głównego artykułu lub listy produktów usuwa ich właściwy HTML z pierwszej odpowiedzi i pogarsza odporność strony na błąd skryptu.

Gotowy HTML nie tworzy automatycznie poprawnego SEO. Nadal odpowiadasz za statusy HTTP, linki kanoniczne, robots, linkowanie, dane uporządkowane, hreflang, sitemapę i zgodność treści wyspy serwerowej z zasadami cache. Mniejszy koszt JavaScriptu może pomóc wydajności, ale framework nie gwarantuje rankingu, indeksacji ani cytowania przez system AI.

Głębiej temat SEO w Astro rozbieram w osobnym artykule.

Audyt techniczny i optymalizacja pod kątem SEO i GEO.
Audyt techniczny SEO

Często zadawane pytania

Czy Islands Architecture to to samo, co Partial Prerendering w Next.js?

Nie, choć oba wzorce pozwalają łączyć różne strategie na jednej stronie. PPR w Next.js dotyczy statycznej powłoki i dynamicznych fragmentów renderowanych na serwerze. Server Components nie są hydratowane, natomiast Client Components dostają JavaScript. Astro Client Islands wyznaczają niezależne granice hydratacji, a Server Islands odraczają osobne renderowanie fragmentu na serwerze. Wynik zależy od liczby granic i kodu.

Czy wyspy mogą się ze sobą komunikować?

Tak. Oddzielne wyspy nie współdzielą automatycznie kontekstu jednego drzewa React lub Vue, ale mogą używać Nano Stores, zdarzeń DOM, parametrów URL, pamięci przeglądarki albo stanu po stronie serwera. Jeśli komponenty wymagają bardzo ścisłej synchronizacji, prostsze może być połączenie ich w jedną wyspę.

Ile wysp na stronie to za dużo?

Nie istnieje uniwersalny limit. Bundler może współdzielić zależności między wyspami, więc koszt nie rośnie idealnie liniowo. Mierz łączny i początkowy JavaScript, liczbę żądań, czas wykonywania oraz INP. Łącz wyspy wtedy, gdy zmniejsza to duplikację lub upraszcza wspólny stan, ale nie twórz przez to jednego monolitycznego drzewa.

Czy mogę mieć React Context dzielone między wyspami?

React Context działa wewnątrz jednej wyspy React, ale nie obejmie dwóch osobno hydratowanych korzeni. Do stanu współdzielonego między wyspami Astro rekomenduje Nano Stores. Zależnie od rodzaju danych możesz też wykorzystać URL, zdarzenia DOM, localStorage albo stan serwerowy.

Czy Server Islands wymagają Cloudflare?

Nie. Wymagają jednak adaptera wspierającego renderowanie na żądanie i poprawnego wdrożenia endpointu wyspy na wybranej platformie. Przed wyborem hostingu sprawdź zgodność konkretnego adaptera, zachowanie cache, cookies, region wykonania i limity funkcji.

O autorze

Maciej Sala

Maciej Sala — konsultant technologiczny produktów cyfrowych i web developer z bogatym doświadczeniem w marketingu internetowym oraz SEO. Na co dzień pracuje z Reactem, Next.js i TypeScriptem, a ostatnio także z Astro i narzędziami do automatyzacji procesów AI. Sprawnie łączy perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat był związany z branżą gier wideo jako project manager i game designer. Absolwent historii na Uniwersytecie Jagiellońskim oraz studiów podyplomowych z marketingu internetowego na AGH w Krakowie. Po godzinach trenuje na siłowni, maluje figurki i rozwija własne projekty.

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną
LH.pl – Hosting Mango

Biblioteka wiedzy na temat Astro

Czytaj dalej

Zobacz więcej wpisów
Astro vs Next.js w 2026: porównanie frameworków

Astro czy Next.js? Wybór frameworka musi być dokładnie przemyślany, zanim pojawi się pierwszy commit. Jeśli stoisz przed takim właśnie wyborem, w tym artykule staram się wykazać, w jakich obszarach najlepiej sprawdza się Astro , a w jakich będzie dominował Next.js .

Maciej Sala

Maciej Sala

Founder StriveLab

Łączenie React Vue i Svelte w architekturze wysp Astro

Zero JavaScript by default to chwytliwy slogan. Architektura, którą on opisuje, to coś większego: cały projekt może być statycznym HTML, a interaktywność jest precyzyjnie rozmieszczonymi wyspami. Każda wyspa to niezależna jednostka z własnym frameworkiem, własnym cyklem hydratacji i własnym kosztem runtime. React, Vue, Svelte i Solid działają na jednej stronie, pod jedną konfiguracją Astro. To nie eksperyment, lecz strategia migracji i narzędzie dla organizacji, które nie mogą sobie pozwolić na przepisanie wszystkiego od zera.

Maciej Sala

Maciej Sala

Founder StriveLab

Server Islands w Astro: dynamiczne fragmenty na statycznej stronie

Server Islands pozwalają pozostawić główny HTML statyczny, a wybrane fragmenty renderować na serwerze po załadowaniu strony. To przydatny model dla koszyka, avatara, stanu magazynowego lub rekomendacji, ale wymaga adaptera, dodatkowych żądań i świadomej polityki cache.

Maciej Sala

Maciej Sala

Founder StriveLab

LH.pl – Cloud Server 1C4G