W tym artykule omawiam pięć dyrektyw klienta: kiedy po nie sięgać, kiedy ich unikać i jakie błędy najczęściej wracają w audytach stron na Astro.
Po co są dyrektywy hydratacji client:* w Astro?
Astro domyślnie nie wysyła JavaScriptu do przeglądarki. Jeśli element z Reacta, Vue albo Svelte ma być interaktywny, musisz jawnie określić, kiedy pobrać jego kod i przeprowadzić . Brak automatycznego ładowania całego runtime'u to fundament architektury wysp i jej największa zaleta.
Jeżeli nie wiesz, czym są wyspy w Astro, zacznij od wpisu o Islands Architecture.
Dyrektywa to kontrakt wydajnościowy: wskazujesz frameworkowi, kiedy statyczny HTML ma dostać logikę po stronie klienta. Dzięki temu Astro może wyrenderować bazową treść bez hydratacji, a JavaScript wysłać tylko tam, gdzie jest naprawdę potrzebny.
Jest przy tym jedno ważne ograniczenie: propsy przekazywane do wyspy muszą być serializowalne. Astro zapisuje je w HTML, więc funkcje, instancje klas czy referencje do innych komponentów nie przejdą. Takie zależności trzeba przenieść do środka wyspy albo zastąpić danymi, które da się zapisać jako JSON.
client:load: natychmiastowa hydratacja komponentu
client:load pobiera i uruchamia kod JavaScript komponentu jak najszybciej, kiedy tylko przeglądarka przetworzy HTML. Jest to najbardziej agresywna dyrektywa i powinna być zarezerwowana dla elementów, które muszą działać od razu.
Kiedy używać client:load:
Nawigacja główna z rozwijanym menu, które prawdopodobnie użytkownik otworzy, jako pierwsze.
Przycisk CTA w głównej sekcji (hero), który musi otworzyć okno modalne.
Komponent do zmiany motywu (ciemny/jasny), który ma zareagować na preferencje użytkownika bez migotania strony.
Kiedy NIE używać client:load:
Formularze kontaktowe w stopce, ponieważ do nich użytkownik musi przewinąć stronę i dlatego
client:visiblew zupełności wystarczy.Komentarze pod wpisem (z analogicznego powodu, jak wyżej).
Galeria zdjęć, którą widać dopiero po kliknięciu w miniaturkę.
Kluczem do sukcesu jest selektywność. Każdy nieuzasadniony client:load to kilobajty blokujące i . Oznaczenie wszystkich wysp jako client:load niszczy całą przewagę wydajnościową Astro — i stawia Cię z powrotem na starcie Next.js, tyle że w innym ekosystemie.
client:idle: hydratacja, gdy przeglądarka jest bezczynna
client:idle czeka na wywołanie — moment, w którym przeglądarka zakończyła krytyczne zadania i procesor ma wolny cykl. Jeśli przeglądarka nie obsługuje requestIdleCallback, Astro używa zdarzenia load; w nowszych wersjach możesz też ustawić limit oczekiwania przez client:idle={{ timeout: 500 }}.
Kiedy używać:
Komponenty ważne, ale nie krytyczne dla pierwszej interakcji — zapis na newsletter, widżet czatu, baner zgody na pliki cookie. Przy zgodach marketingowych tryb ładowania komponentu musi być spójny z tym, kiedy uruchamiasz skrypty śledzące.
Widżety dostawców zewnętrznych opakowane w komponent frameworka, które wpływają na interaktywność, ale nie stanowią priorytetu.
- Przyciski udostępniania w mediach społecznościowych.
Kiedy NIE używać:
Elementy znajdujące się poza początkowo widocznym obszarem strony, których załadowanie można odłożyć używając
client:visible.Krytyczne elementy interfejsu (okna modalne, główna nawigacja).
W praktyce client:idle często przesuwa hydratację poza krytyczny start strony — i właśnie takie odroczenie potrafi obniżyć koszt JavaScriptu widoczny w TBT oraz w diagnostyce Lighthouse.
client:visible: hydratacja po wejściu komponentu w viewport
client:visible wykorzystuje , aby pobrać i uruchomić JavaScript dopiero wtedy, gdy dana sekcja pojawi się w widocznym obszarze ekranu. Jeśli użytkownik do niej nie przewinie, paczka JS w ogóle nie zostanie pobrana.
client:visible to domyślna rekomendacja dla elementów poniżej linii przewijania. Daje realną oszczędność, bo kod ładuje się dopiero wtedy, gdy jest szansa na interakcję.
Kiedy używać client:visible:
- Sekcja komentarzy pod artykułem.
- Formularz kontaktowy w stopce lub na samym dole strony.
- Galeria zdjęć znajdująca się poniżej opisu produktu.
Kalkulator lub interaktywny widżet osadzony w środku wpisu.
- Karuzela z logotypami klientów.
Kiedy NIE używać client:visible:
Elementy pierwszego ekranu, bo są widoczne od razu. W takim miejscu
client:visiblenie optymalizuje ładowania, tylko dokłada narzut obserwatora (IntersectionObserver).Wyspy współdzielące stan z innymi częściami interfejsu, bo opóźniona hydratacja może spowolnić synchronizację danych.
Możesz też skonfigurować parametr client:visible, aby rozpocząć pobieranie kodu JS zanim komponent fizycznie wejdzie w widoczny obszar (prefetching):
Dzięki temu kod ładuje się, gdy komponent znajduje się np. 200 pikseli poniżej aktualnego widoku. Użytkownik nie odczuje żadnego opóźnienia, a w przypadku gdy w ogóle tam nie przewinie, oszczędzamy zasoby sieciowe.
client:media: hydratacja po spełnieniu media query
client:media uruchamia hydratację dopiero po spełnieniu wskazanego media query. Przykładowo, na smartfonie DesktopSidebar nie pobierze swojego kodu JS, a MobileNav zostanie pominięty na komputerze stacjonarnym. Warunek jest nasłuchiwany na żywo: po obrocie tabletu albo zwężeniu okna hydratacja ruszy w momencie dopasowania, ale już zhydratowany komponent pozostaje interaktywny nawet po późniejszej zmianie rozmiaru.
Kiedy używać client:media:
Elementy interfejsu przeznaczone wyłącznie na urządzenia mobilne, czyli menu typu hamburger, wysuwane panele dolne (bottom sheets), galerie obsługujące gesty przesunięcia (swipe).
Elementy wyłącznie desktopowe, takie jak rozbudowane menu rozwijane po najechaniu kursorem, skomplikowane filtry wykorzystujące mechanizm przeciągnij i upuść.
Responsywne widżety, które mają kompletnie inną logikę działania w zależności od rozmiaru ekranu.
Kiedy NIE używać client:media:
Kiedy komponent dostosowuje się tylko wizualnie (za pomocą CSS media queries), ale nie zmienia logiki biznesowej.
Gdy zachowanie różni się zaledwie szczegółem, wtedy prościej jest użyć
client:visiblei wewnątrz komponentu weryfikować warunki przezwindow.matchMedia.
Po tę dyrektywę sięgam rzadko, ale w specyficznych sytuacjach, np. przy ciężkim wysuwanym panelu mobilnym, który na desktopie nie istnieje, pozwala zaoszczędzić dziesiątki kilobajtów transferu. Innymi słowy, wdrażamy ją tylko wtedy, gdy logika po obu stronach ekranu jest wyraźnie inna.
client:only: komponent wyłącznie po stronie klienta
client:only to sygnał dla Astro, żeby nie renderować komponentu po stronie serwera () i wygenerować go wyłącznie w przeglądarce. Działa to odwrotnie do pozostałych dyrektyw.
Kiedy używać client:only:
Komponenty zależne w fazie renderowania od obiektów globalnych przeglądarki takich jak
window,documentczylocalStorage, ponieważ bez tego proces SSR zakończyłby się błędem.Biblioteki, które nie posiadają wsparcia dla SSR (np. niektóre nakładki na Three.js, react-leaflet, edytory tekstu typu WYSIWYG).
Komponenty bazujące na danych z bazy
IndexedDBlub service workerów.Elementy, których wygląd jest bardzo mocno uzależniony od dokładnego rozmiaru okna, a wersja wyrenderowana na serwerze i tak wymagałaby natychmiastowego przebudowania przez JS.
Kiedy NIE używać client:only:
We wszystkich innych przypadkach. Użycie
client:onlydezaktywuje mechanizm SSR, przez co rezygnujesz z błyskawicznego serwowania gotowej treści. Zamiast tego zmuszasz użytkownika do oczekiwania, aż pobierze się JS i wygeneruje komponent bezpośrednio w jego przeglądarce.
Sprawdzoną praktyką przy korzystaniu z client:only jest dodanie zastępczego szkieletu (placeholdera):
Dzięki temu zabiegowi użytkownik na czas wczytywania widzi zarezerwowaną przestrzeń, układ strony nie skacze, a wskaźnik przesunięcia układu () pozostaje nienaruszony, co jest ważne dla zielonych wyników .
Porównanie dyrektyw client:* w Astro
| Dyrektywa | Kiedy ładuje JS | Kiedy używać | Kiedy unikać |
|---|---|---|---|
client:load | Natychmiast | Krytyczne interakcje na pierwszym ekranie (nawigacja, główne przyciski) | Elementy widoczne dopiero po przewinięciu |
client:idle | Gdy przeglądarka jest bezczynna | Ważne, ale nie priorytetowe elementy (newsletter, czat) | Krytyczny interfejs, komponenty reagujące na przewijanie |
client:visible | Gdy element wchodzi w pole widzenia | Wszystko poniżej pierwszego ekranu | Elementy widoczne od razu po załadowaniu |
client:media | Gdy spełnione są reguły media query | Interfejsy specyficzne tylko dla mobile / desktop | Gdy zmienia się wyłącznie wygląd, a nie logika |
client:only | Natychmiast, ale bez SSR — HTML powstaje dopiero w przeglądarce | Biblioteki niekompatybilne z SSR, wymagające okna przeglądarki | Każdy element, który można bez problemu wyrenderować na serwerze |
Budżet hydratacji w Astro
W większych projektach warto ustalić limit kodu klienta dla każdego typu wyspy, ponieważ określenie takiego budżetu chroni przed sytuacją, w której strona Astro ma być lekka, a w praktyce wysyła kilka masywnych paczek.
- maksymalna liczba wysp z client:load na pierwszym ekranie
- 1–2maksymalna liczba wysp z client:load na pierwszym ekranie
- JavaScript dla elementów czysto wizualnych bez interakcji
- 0 KBJavaScript dla elementów czysto wizualnych bez interakcji
- Pierwszy ekran: maksymalnie 1–2 interaktywne wyspy z
client:load. - Niższe sekcje strony:
client:visiblejako domyślny wybór. - Detale wizualne i dekoracje: brak hydratacji, chyba że wprost wpływają na konwersję.
- Komponenty wymagające API przeglądarki:
client:only— brak SSR jest w tym wypadku nieunikniony. - Zależności współdzielone: regularna weryfikacja, czy mała wyspa nie importuje całej biblioteki wykresów, edytora WYSIWYG albo kitu.
Najczęstsze błędy przy dyrektywach client:*
W audytach stron Astro notorycznie spotykam trzy te same kategorie błędów:
1. Nadużywanie client:load. Przykładem jest serwis na Astro, który ma osiem wysp oznaczonych client:load i ładuje cały ich JavaScript już na starcie. W takiej konfiguracji architektura wysp istnieje głównie na papierze.
2. Layout owinięty w jeden wielki React z client:load. Programista przyzwyczajony do Next.js może odruchowo budować Layout.tsx z nagłówkiem, treścią i stopką, a potem oznaczyć całość client:load. Fundament strony musi być .astro, natomiast komponenty frameworkowe osadzamy punktowo i wyłącznie tam, gdzie konieczna jest interakcja.
3. client:only bez elementu zastępczego. Komponent ładuje się po 1,5 s, strona nieprzyjemnie skacze, a CLS niebezpiecznie rośnie. Zawsze ustaw kontener zastępczy z odpowiednią wysokością na czas ładowania.
Praktyczny przykład: karta produktu e-commerce w Astro
Przeanalizujmy dobór odpowiednich dyrektyw przy projektowaniu standardowej podstrony produktowej:
Taka konfiguracja od razu pokazuje pełną strukturę strony, bez oczekiwania na pobranie skryptów. Krytyczne strefy interfejsu (galeria zdjęć, przycisk zakupu) są szybko hydratowane i gotowe do akcji, a skrypty opinii ładują się dopiero wtedy, gdy użytkownik przewinie stronę do danej sekcji. Elementy o niższym priorytecie, takie jak karuzela sugerująca inne produkty, nie opóźniają pierwszego renderowania zawartości na ekranie.
Audyt hydratacji własnej strony Astro
Jeśli rozwijasz już projekt w Astro, wdróż ten czteropunktowy audyt:
- Przeszukaj kod pod kątem
client:load— każda taka deklaracja musi być nieodzowna na pierwszym ekranie. - Zmień na
client:visiblekażdą dyrektywę dla elementów poza pierwszym ekranem. - Znajdź każde
client:only— udokumentuj komentarzem, dlaczego SSR jest tu niemożliwy. Część przypadków da się przepisać. - Uruchom Lighthouse Mobile. Pilnuj zwłaszcza TBT, INP, CLS i LCP; TBT poniżej 200 ms to dobry punkt odniesienia dla strony z lekką interaktywnością.
Jeśli chcesz zlecić profesjonalny audyt techniczny SEO Twojej witryny w Astro — wejdź na wyższy poziom i odezwij się.
