Przejdź do treści

Jak zdobyć 100/100 w Lighthouse z Astro? Case Study

Jak zdobyć 100/100 w Lighthouse z Astro? Case study strony usługowej: astro:assets, Fonts API, client:visible, View Transitions, SSG, cache i Core Web Vitals.

Maciej Sala

Founder StriveLab

9 min czytaniaOpublikowano 29 maja 2026 (Aktualizacja 6 lipca 2026)

Mamy stronę usługową w Astro: hero z obrazem, sekcje oferty, dowód społeczny, formularz kontaktowy jako wyspa React, analityka i czat. Świeży build dał 94/100 na mobile — wysoko, bo Astro nie wysyła zbędnego JavaScriptu. Ale klient chciał komplet. wskazał obszary do domknięcia: obrazy, fonty, skrypty third-party, selektywną hydratację, dostępność i konfigurację produkcyjnego hostingu.

Lighthouse Mobile po optymalizacji
94 → 100Lighthouse Mobile po optymalizacji
LCP po uporządkowaniu obrazu hero
2.1 s → 0.9 sLCP po uporządkowaniu obrazu hero
CLS po wdrożeniu Fonts API
0.09 → 0.00CLS po wdrożeniu Fonts API

W nowszych raportach Lighthouse warto sprawdzać też Przeglądanie Agentowe. Astro ma tu naturalną przewagę, bo statyczny HTML, semantyka i niski CLS są dokładnie tym, co pomaga zarówno ludziom, jak i agentom AI. WebMCP zostawiłbym na projekty transakcyjne, ale llms.txt i stabilny layout są tanimi wygranymi.

Dlaczego Astro startuje wysoko w Lighthouse

Zanim zaczniemy optymalizować, warto zrozumieć, skąd te 94 punkty na starcie. Astro renderuje stronę jako statyczny HTML i domyślnie nie wysyła do przeglądarki frameworkowego JavaScriptu. Sekcje takie jak hero, oferta czy stopka to komponenty .astro, czyli czysty HTML i zero kosztu po stronie klienta.

To strukturalna przewaga nad aplikacyjnym modelem React/Next, gdzie nawet statyczna strona ładuje runtime frameworka. Szerzej rozkładam to w artykule Astro.js vs Next.js. Dla Lighthouse oznacza to niski i dobry punkt wyjścia pod bez żadnej pracy.

Ostatnie punkty to nie walka z frameworkiem — to dopracowanie zasobów, które framework przepuszcza bez zmian: obrazów, fontów i skryptów zewnętrznych.

Krok 1: Obrazy — astro:assets zamiast surowego <img>

Największy problem był w hero. Obraz wstawiony jako surowy <img> ładował się w pełnej wadze, bez WebP/AVIF i bez wymiarów. Efektem był duży i przesunięcia układu.

Rozwiązaniem jest komponent <Image> z :

Code
---
import { Image } from 'astro:assets'
import heroImage from '../assets/hero.jpg'
---
 
<Image
  src={heroImage}
  alt="Strona usługowa po optymalizacji"
  width={1200}
  height={630}
  loading="eager"
  fetchpriority="high"
  format="webp"
/>

Trzy rzeczy zadziałały naraz. WebP/AVIF generuje się automatycznie podczas builda, bez ręcznej obróbki ani pipeline'u graficznego. Wymiary width i height sprawiają, że przeglądarka rezerwuje miejsce jeszcze przed załadowaniem obrazu, więc układ nie skacze. loading="eager" z fetchpriority="high" wyciąga obraz hero poza kolejkę i ładuje go jako pierwszy — bo to on jest elementem LCP, który Lighthouse mierzy. W efekcie LCP spadł z 2.1 s do 0.9 s, a pozostałe obrazy dostały loading="lazy" automatycznie.

Krok 2: Fonty — Fonts API zamiast Google Fonts z CDN

Drugim źródłem były Google Fonts ładowane z zewnętrznego : zewnętrzny request, FOUT i skok układu, gdy właściwy krój się doczytał.

Rozwiązaniem jest Fonts ustabilizowane w Astro 6 (top-level klucz fonts), które hostuje krój lokalnie i generuje dopasowane fallbacki:

Code
// astro.config.mjs
import { defineConfig, fontProviders } from 'astro/config'
 
export default defineConfig({
  fonts: [
    {
      provider: fontProviders.google(),
      name: 'Inter',
      cssVariable: '--font-inter',
      weights: ['400', '600', '700'],
      subsets: ['latin', 'latin-ext'],
    },
  ],
})

Astro podczas builda pobiera krój, kopiuje go do lokalnych zasobów, generuje font-display: swap z fallbackiem o zbliżonych metrykach i dodaje preload. Produkcja nie odpytuje serwerów Google, a tekst nie skacze przy podmianie kroju. CLS z fontów spadł z 0.09 do 0.00. Dla polskich znaków kluczowy jest latin-ext w subsets.

Krok 3: Skrypty third-party — leniwe ładowanie

Analityka i widget czatu ładowały się synchronicznie, blokując główny wątek i podbijając TBT. W Astro skrypty kontrolujesz dyrektywami i atrybutami ładowania:

Code
<!-- Skrypt niekrytyczny: ładuj asynchronicznie, nie blokuj parsowania -->
<script src="https://analytics.example.com/script.js" async></script>

Dla cięższych integracji (czat, embedy) najlepszą strategią jest załadowanie ich dopiero po interakcji albo gdy wejdą w viewport — przez wyspę z client:visible albo client:idle, zamiast wpinać skrypt w <head>. Wszystko, co nie jest krytyczne dla pierwszego renderu, schodzi poza ścieżkę krytyczną.

W wyniku tych działań TBT spadł poniżej progu, a INP ustabilizował się na bardzo niskim poziomie.

Krok 4: Dyrektywy client — selektywna hydratacja

To najważniejsza dźwignia specyficzna dla Astro. Formularz kontaktowy był wyspą React z client:load — hydratował się natychmiast, mimo że użytkownik dociera do niego dopiero po przewinięciu strony.

Zmiana na client:visible:

Code
---
import ContactForm from '../components/ContactForm.tsx'
---
 
<!-- Hydratacja dopiero, gdy formularz wejdzie w viewport -->
<ContactForm client:visible />

Każdy client:load to JavaScript blokujący wątek od razu po załadowaniu. client:visible odkłada koszt do momentu, gdy komponent jest realnie potrzebny — a jeśli użytkownik nie doscrolluje, kod nie pobiera się wcale. To główny mechanizm, którym w Astro sterujesz INP i TBT. Szerzej rozkładam dyrektywy w osobnym artykule.

Reguła: client:load tylko dla interfejsu krytycznego na pierwszym ekranie. Wszystko poniżej — client:visible.

Krok 5: Usuń wyspy tam, gdzie wystarczy HTML, CSS i View Transitions

Najłatwiejszy JavaScript do optymalizacji to taki, którego w ogóle nie wysyłamy do przeglądarki. W Astro warto więc przejrzeć wszystkie wyspy React, Vue albo Svelte i dokładnie przemyśleć, czy dany element naprawdę potrzebuje stanu po stronie klienta?

Prosty hamburger, rozwijana sekcja FAQ, podstawowa animacja wejścia, hover, przejście między podstronami albo zakładki w małej sekcji często nie wymagają frameworka. Wystarczy semantyczny HTML, CSS, ewentualnie kilka linii natywnego JavaScriptu albo View Transitions:

Code
---
import { ClientRouter } from 'astro:transitions'
---
 
<head>
  <ClientRouter />
</head>
Code
<a href="/oferta/" transition:name="main-cta">Zobacz ofertę</a>

W tym wszystkim, chodzi o brak tam, gdzie nie ma realnej interaktywności. W sytuacji, kiedy komponent tylko pokazuje i chowa treść, animuje kartę albo zmienia stan wizualny, zacznij od HTML/CSS. Wyspę frameworka zostaw dla formularzy, konfiguratorów, map, kalkulatorów i elementów, które naprawdę mają logikę po stronie klienta.

Krok 6: Dostępność i SEO — łatwe punkty, które często uciekają

Lighthouse Performance to tylko jedna kategoria, bo jeśli celujesz w komplet wyników, musisz domknąć też Accessibility i SEO, a w 2026 roku pośrednio również czytelność dla agentów AI.

Minimum, które sprawdzam przy stronie Astro:

  • Jeden czytelny h1 na stronie i logiczna hierarchia nagłówków bez skoków z h2 do h4.

  • Kontrast tekstu zgodny z WCAG, szczególnie na przyciskach, kartach i jasnych gradientach.

  • Atrybuty alt dla obrazów niosących informację; puste alt="" tylko dla dekoracji.

  • Prawdziwe <button> dla akcji i <a> dla przejść, zamiast klikalnych div-ów.

  • Unikalne title, description, canonical i Open Graph dla każdej ważnej podstrony.

W Astro często robię to przez wspólny komponent layoutu albo BaseHead.astro, który wymusza metadane i nie pozwala zapomnieć o adresie kanonicznym. To nie podbija samego Performance, ale domyka Lighthouse SEO, poprawia podglądy social media i daje agentom AI czytelniejszą strukturę dokumentu.

Krok 7: SSG, cache i CDN — produkcja też jest częścią wyniku

Astro domyślnie świetnie nadaje się do stron statycznych: blogów, portfolio, dokumentacji i stron usługowych. Jeśli nie potrzebujesz renderowania na żądanie, trzymaj projekt w trybie . Wtedy podczas builda powstają statyczne pliki HTML, CSS i JS, które CDN może serwować z brzegu sieci bez zimnych startów i bez pracy serwera przy każdym wejściu.

To ma bezpośredni wpływ na . Lighthouse lokalnie nie pokaże całej prawdy, bo prawdziwy wynik zależy od hostingu, kompresji i cache. Na produkcji sprawdź:

  • HTML serwowany z krótkim, kontrolowanym cache albo z mechanizmem purge po deployu.

  • Assety z hashem w nazwie, np. CSS, JS, fonty i obrazy, z długim Cache-Control: public, max-age=31536000, immutable.

  • Kompresję Brotli albo Gzip dla HTML, CSS, JS, SVG i plików tekstowych.

  • CDN, np. Cloudflare, Netlify, Vercel albo Cloudflare Pages, zamiast serwowania statycznej strony z jednego odległego serwera.

  • Test PageSpeed Insights na produkcyjnym URL po deployu, nie tylko Lighthouse w trybie dev.

Same techniki optymalizacji pozostają niezmienne, poczynając od kompresji grafik i fontów, po leniwe ładowanie skryptów. Różnica tkwi w punkcie wyjścia: Next.js na starcie niesie ze sobą narzut w postaci runtime'u Reacta, podczas gdy Astro domyślnie nie serwuje żadnego kodu JavaScript. Ostatecznie osiągnięcie wyniku 100/100 na obu platformach wymaga dokładnie tej samej dyscypliny technicznej.

Wynik końcowy optymalizacji Lighthouse 100/100 w Astro

MetrykaPrzedPo
Lighthouse Mobile94100
Lighthouse Desktop98100
LCP2.1 s0.9 s
INP90 ms40 ms
CLS0.090.00
TBT180 ms30 ms

Lista kontrolna optymalizacji Astro pod Lighthouse i Core Web Vitals

Dziewięć punktów, które w tym case study dały największy efekt i które warto wbudować w każdy projekt Astro od początku:

  • Obrazy przez astro:assets. <Image> z width/height, loading="eager" i fetchpriority="high" na elemencie LCP.
  • Fonty przez Fonts API (Astro 6) z latin-ext dla polskiego — samodzielne hostowanie zamiast Google Fonts z CDN eliminuje FOUT i layout shift.
  • client:visible jako domyślna dyrektywa; client:load tylko dla interfejsu krytycznego na pierwszym ekranie.
  • Proste interakcje najpierw HTML/CSS/View Transitions, a dopiero potem wyspa React, Vue albo Svelte.
  • Skrypty third-party async/defer albo jako wyspa client:idle/client:visible, a nigdy synchronicznie w <head>.
  • Semantyczne nagłówki, kontrast, alt dla obrazów i prawdziwe linki oraz przyciski zamiast klikalnych div-ów.
  • Unikalne metadane SEO: title, description, canonical i Open Graph dla każdej ważnej podstrony.
  • SSG dla stron treściowych oraz statyczne assety z długim cache na CDN.
  • Testuj na produkcyjnym URL przez PageSpeed Insights, nie tylko lokalnie, ponieważ Lighthouse w dev nie mierzy TTFB ani opóźnień CDN.

Astro vs Next.js, czyli inny start, ale ten sam cel.

Ten case study jest świadomym bliźniakiem mojego case study 100/100 w Next.js. Różnica nie leży w technikach: obrazy, fonty, lazy loading skryptów obowiązują tak samo. Leży w punkcie startu: Next.js zaczyna niżej (runtime React do okiełznania), Astro wyżej (zero JS domyślnie), ale obie strony dochodzą do 100/100 tą samą dyscypliną.

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

Często zadawane pytania

Czy Astro startuje z lepszym Lighthouse niż Next.js?

Tak, na starcie. Astro domyślnie wysyła zero JavaScriptu, więc świeży projekt często ma Lighthouse Performance powyżej 95 bez optymalizacji. To strukturalna przewaga, ponieważ w Next.js do podobnego wyniku dochodzisz świadomymi decyzjami (Server Components, kontrola Client Components). Ale 100/100 w Astro też wymaga uwagi przy obrazach, fontach i skryptach third-party.

Co najczęściej psuje Lighthouse w Astro?

Zazwyczaj chodzi o trzy rzeczy: nadużycie client:load dla komponentów, które nie muszą być interaktywne od razu. Kolejną rzeczą są obrazy bez astro:assets (brak WebP/AVIF i wymiarów, stąd CLS) oraz ciężkie skrypty third-party (analityka, czat) ładowane synchronicznie.

Czy 100/100 w Lighthouse to właściwy cel?

Nie jako cel sam w sobie. 100/100 to dobry sygnał technicznej dyscypliny, ale liczą się realne Core Web Vitals z pola (dane od prawdziwych użytkowników) i konwersja. Powyżej 90 w zupełności wystarcza; gonienie za ostatnimi punktami kosztem funkcjonalności rzadko się opłaca.

Czy wynik 100 na localhost równa się 100 na produkcji?

Niekoniecznie. Lighthouse lokalnie nie mierzy TTFB serwera, opóźnień CDN ani warunków sieciowych prawdziwych użytkowników. Zawsze testuj na produkcyjnym URL, najlepiej przez PageSpeed Insights, który łączy dane laboratoryjne z polowymi.

Czy dyrektywy client w Astro wpływają na Lighthouse?

Bardzo. Każdy client:load to JavaScript blokujący główny wątek (rośnie TBT, spada INP). Domyślnym wyborem powinien być client:visible — komponent hydratuje się dopiero, gdy wejdzie w viewport, a często wcale. Selektywna hydratacja to główna dźwignia wyniku w Astro.

O autorze

Maciej Sala

Maciej Sala — Product Manager i Frontend 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 rozwijam własne projekty.

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

Skontaktuj się ze mną

Biblioteka wiedzy na temat Astro

Czytaj dalej

Zobacz więcej wpisów
Jak osiągnąć 100/100 w Lighthouse Performance w Next.js? Case study

Mamy tu typową stronę usługową zbudowaną w Next.js, wyposażoną w Google Analytics, Google Tag Manager , prosty formularz kontaktowy, galerię zdjęć i animacje. Na początku testy PageSpeed Insights pokazały wyniki: 67/100 na urządzeniach mobilnych i 89/100 na komputerach stacjonarnych.

Maciej Sala

Maciej Sala

Founder StriveLab

SEO w Astro — Core Web Vitals, dane uporządkowane i techniczny fundament rankingu w 2026

Astro dostarcza przyjazność SEO już na poziomie architektury, gwarantując świetne wyniki w Lighthouse dzięki brakowi domyślnego JavaScriptu i statycznemu renderowaniu HTML. Jednak prawdziwa widoczność w Google oraz systemach AI to efekt świadomych decyzji inżynieryjnych, a nie tylko wyboru frameworka. W tym artykule rozbieram na części pierwsze każdą z nich: od Core Web Vitals, przez metadane i schema.org , aż po optymalizację GEO / AEO .

Maciej Sala

Maciej Sala

Founder StriveLab

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