StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN

Astro

Ultraszybkie projekty, łączące lekkość ze skalowalnością.

Next.js

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.

React

Połączenie intuicyjności z wydajnością, które zapewnia bezproblemową skalowalność kodu.

SEO & Performance

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

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Doradztwo produktowe

Połączenie perspektywy produktu, developera i marketingu w jednym miejscu

StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN

Astro

Ultraszybkie projekty, łączące lekkość ze skalowalnością.

Next.js

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.

React

Połączenie intuicyjności z wydajnością, które zapewnia bezproblemową skalowalność kodu.

SEO & Performance

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

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Doradztwo produktowe

Połączenie perspektywy produktu, developera i marketingu w jednym miejscu

Astro

Ultraszybkie projekty, łączące lekkość ze skalowalnością.

Next.js

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.

React

Połączenie intuicyjności z wydajnością, które zapewnia bezproblemową skalowalność kodu.

SEO & Performance

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

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Doradztwo produktowe

Połączenie perspektywy produktu, developera i marketingu w jednym miejscu

RealizacjeO mnieBlog
Porozmawiajmy
PL
EN

Nowoczesne strony internetowe dla firm, które myślą odważnie.

Przewiń do góry

Nazwa

StriveLab Maciej Sala

NIP

6772218995

REGON

524008527

E-mail

contact@strivelab.pl

Usługi główne
  • Tworzenie stron internetowych
  • Strony internetowe Next.js
  • Strony internetowe Astro
  • Strony internetowe React
Inne usługi
  • Usługi
  • SEO & Performance Sprint
  • QA & Stabilizacja
  • Konsultacje Product / Delivery
  • Automatyzacja Procesów AI
  • Aplikacje webowe Next.js
  • Współpraca ciągła
Strony
  • O mnie
  • Usługi
  • Realizacje
  • Blog

© 2026 StriveLab.pl

Polityka prywatności
Next.jsWydajnośćSEO

Pagespeed 100/100 w Next.js — case study optymalizacji strony usługowej

Jak osiągnąć wynik 100/100 w PageSpeed Insights dla strony Next.js? Case study optymalizacji LCP, INP i CLS — fonty, obrazy, JavaScript, third-party scripts i Server Components.

OpublikujLinkedInFacebookWyślij
Autor
Maciej Sala
Opublikowano
10 kwietnia 2026 14:40
Czytanie
4 min czytania
Aktualizacja
25 maja 2026 10:55

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 – czyli standardowy zestaw. Na początku testy PageSpeed Insights pokazały wyniki: 67/100 na urządzeniach mobilnych i 89/100 na komputerach stacjonarnych.

Artykuł w skrócie

  • Fonty przez next/font — eliminacja layout shift fontów i blokowania renderowania to często pierwsze 5–10 punktów w PageSpeed Insights.
  • next/image z priority i sizes — hero image z priority ładuje się poza kolejką lazy loading; poprawny sizes redukuje rozmiar pliku.
  • Third-party scripts leniwie — GTM i inne skrypty analityczne ładuj przez next/script ze strategy="lazyOnload" lub strategy="afterInteractive".
  • Client Components do minimum — każdy "use client" powiększa bundle; izoluj interaktywność w małych komponentach zamiast opakowywać duże sekcje.
  • Testuj na produkcji — Lighthouse lokalnie nie mierzy TTFB serwera; wynik 100 w dev nie gwarantuje tego samego na deployowanej stronie.

Punkt wyjścia: typowa strona usługowa

Lighthouse wskazało główne problemy: duże zasoby JavaScript (GTM) blokujące renderowanie, niezoptymalizowane obrazy, brak odpowiednich wskazówek dla przeglądarki (resource hints) oraz nadmierne przesunięcia układu strony (layout shift) związane z ładowaniem czcionek.

Naszym celem było poprawienie rzeczywistych wskaźników Core Web Vitals to zestaw metryk Google oceniających realne doświadczenie użytkownika: LCP (szybkość ładowania), INP (responsywność) i CLS (stabilność wizualna). Wpływają na ranking i konwersję., a przy okazji osiągnięcie jak najwyższego wyniku w testach laboratoryjnych Lighthouse. Wynik 100/100 zarówno na urządzeniach mobilnych, jak i desktopowych jest możliwy do uzyskania, ale nie powinien być celem za wszelką cenę. Generalnie uzyskanie powyżej 90/100 w zupełności wystarcza.

PageSpeed Mobile po optymalizacji
67 → 100
LCP po uporządkowaniu obrazów i fontów
3.2 s → 1.1 s
JavaScript bundle po ograniczeniu Client Components
210 KB → 85 KB
Uwaga

Wynik 100/100 jest dobrym dowodem technicznej dyscypliny, ale nie jest celem biznesowym. Ważniejsze jest to, czy realni użytkownicy mają szybki LCP, stabilny layout i responsywny formularz na produkcji.

Krok 1: Fonty — eliminacja layout shift

Problem stanowiły Google Fonts ładowane z CDN, czyli Content Delivery Network, to rozproszona sieć serwerów dostarczająca zasoby z węzła najbliższego użytkownikowi; CDN do obrazów dodatkowo transformuje je w locie. powodowały FOUT i CLS (Cumulative Layout Shift) to Core Web Vital mierzący nieoczekiwane przesunięcia elementów podczas ładowania i działania strony. Animacje psują go wtedy, gdy ruszają właściwości layoutowe albo gdy pojawiający się element nie ma zarezerwowanego miejsca..

Rozwiązaniem było użycie next/font z self-hostingiem i size-adjust:

Code
import { Inter } from 'next/font/google'
 
const inter = Inter({
  subsets: ['latin', 'latin-ext'],
  display: 'swap',
  variable: '--font-inter',
})

W wyniku tych działań wyeliminowaliśmy zewnętrzny request do fonts.googleapis.com i uzyskaliśmy spadek CLS z fontów z 0.12 do 0.00.

Krok 2: Obrazy — next/image z priority i sizes

Problem stanowił obraz hero image (LCP, czyli Largest Contentful Paint, mierzy czas do wyrenderowania największego widocznego elementu — oznaczenie go preload przyspiesza jego załadowanie. element) ładował się z opóźnieniem, brak sizes powodował pobieranie zbyt dużych wariantów.

Code
<Image
  src={heroImage}
  alt="Strona internetowa Next.js"
  priority // Najwyższy priorytet dla LCP image
  placeholder="blur"
  sizes="100vw"
  className="h-auto w-full"
/>

Rozwiązaniem jest konwersja wszystkich obrazów na WebP/AVIF automatycznie przez next/image, dodanie sizes do każdego <Image> z precyzyjnymi breakpointami.

W wyniku tych działań LCP spadł z 3.2 s do 1.4 s (a po komplecie optymalizacji z kolejnych kroków zszedł do 1.1 s).

Krok 3: Third-party scripts — lazy loading GTM

Problemem okazał się GTM, czyli Google Tag Manager, pozwala zarządzać tagami i skryptami marketingowymi bez każdej zmiany w kodzie aplikacji. (130 KB), który blokował rendering. GTM ładowany w <head> opóźniał FCP (First Contentful Paint) to czas do wyrenderowania pierwszego fragmentu treści strony — pierwszy sygnał dla użytkownika, że coś się ładuje. o 800 ms.

Rozwiązanie: @next/third-parties z opóźnionym ładowaniem:

Code
// app/layout.tsx
import { GoogleTagManager } from '@next/third-parties/google'
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="pl">
      <body>
        {children}
        <GoogleTagManager gtmId="GTM-XXXXX" />
      </body>
    </html>
  )
}

@next/third-parties automatycznie opóźnia ładowanie GTM i skrypt nie blokuje renderingu.

Alternatywnie, jeśli nie korzystasz z @next/third-parties, ten sam efekt osiągniesz ręcznie przez next/script ze strategy="lazyOnload" — GTM ładuje się dopiero po onload:

Code
'use client'
 
import Script from 'next/script'
 
export function LazyGTM() {
  return (
    <Script
      id="gtm"
      strategy="lazyOnload" // Ładuj po onload
      src={`https://www.googletagmanager.com/gtm.js?id=GTM-XXXXX`}
    />
  )
}

W wyniku tych działań TBT, czyli Total Blocking Time, to łączny czas, w którym główny wątek jest zablokowany i nie reaguje na interakcje użytkownika podczas ładowania. spadł z 420 ms do 80 ms (po minimalizacji Client Components w kroku 4 zszedł finalnie do 60 ms).

Krok 4: JavaScript bundle — minimalizacja Client Components

Zauważyliśmy, że w projekcie było zbyt wiele Client Components. Przykładowo, sekcja hero, nawigacja i stopka były oznaczone jako 'use client', choć w rzeczywistości nie wymagały interaktywności po stronie klienta.

Rozwiązaniem było przekształcenie tych elementów na Server Components wszędzie tam, gdzie było to możliwe. Client Components zostały zachowane wyłącznie dla funkcjonalności wymagających faktycznej interakcji, takich jak przełącznik menu mobilnego, formularz kontaktowy czy animacje związane ze scrollowaniem.

Code
/* PRZED — cały hero jako Client Component
'use client'; // ← niepotrzebne
export function HeroSection() { ... } */
 
/* PO — Server Component (zero JS w bundle) */
export function HeroSection() { ... }

W wyniku tych optymalizacji JavaScript bundle zmalał z 210 KB do 85 KB (gzipped).

Krok 5: Preconnect i DNS prefetch

Metadata API nie służy do dowolnego generowania tagów preconnect i dns-prefetch, więc najprościej dodać je bezpośrednio w <head>:

Code
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="pl">
      <head>
        <link rel="preconnect" href="https://www.googletagmanager.com" />
        <link rel="dns-prefetch" href="https://www.google-analytics.com" />
      </head>
      <body>{children}</body>
    </html>
  )
}

Krok 6: CSS — eliminacja nieużywanych klas

Tailwind CSS z konfiguracją content automatycznie tree-shakuje nieużywane klasy. Upewnij się, że ścieżki są poprawne:

Code
// tailwind.config.ts
const config = {
  content: [
    './app/**/*.{ts,tsx}',
    './components/**/*.{ts,tsx}',
    // NIE: './node_modules/**' — to zaciągnie ogromne CSS
  ],
}

Wynikowy CSS: ~12 KB (gzipped) zamiast pełnych ~300 KB Tailwind.

Krok 7: Animacje bez blokowania

Framer Motion ładowane lazy, ale tylko na stronach z animacjami:

Code
import dynamic from 'next/dynamic'
 
const AnimatedSection = dynamic(() => import('./animated-section'), {
  ssr: false,
  loading: () => <div className="h-96" />,
})

Micro-interactions (hover, tap) zastąpione czystym CSS:

Code
.btn-hover {
  transition: transform 0.15s ease;
}
.btn-hover:hover {
  transform: scale(1.02);
}
.btn-hover:active {
  transform: scale(0.98);
}

Wynik końcowy

Podsumowując wszystkie działania optymalizacyjne dobiliśmy do poniższych wyników:

MetrykaPrzedPo
PageSpeed Mobile67100
PageSpeed Desktop89100
LCP3.2 s1.1 s
INP180 ms45 ms
CLS0.120.00
TBT420 ms60 ms
JS bundle210 KB85 KB
CSS45 KB12 KB

Checklist optymalizacji

Przed każdym deploymentem, warto skorzystać z tej krótkiej checklisty:

  • next/font dla wszystkich fontów (z latin-ext dla polskiego),
  • next/image z priority na LCP element i sizes na każdym obrazie,
  • Third-party scripts z strategy="lazyOnload" lub @next/third-parties,
  • Minimum Client Components — Server Components jako domyślne,
  • Preconnect do zewnętrznych domen,
  • Tailwind z poprawnymi content ścieżkami,
  • Animacje CSS zamiast JS dla micro-interactions,
  • headers() w next.config.ts z cache-control dla statycznych assets.

Werdykt Labu

100/100 w PageSpeed da się osiągnąć w warunkach laboratoryjnych, ale większe znaczenie mają stabilnie, szybkie i dobre Core Web Vitals na produkcji. Największe zyski w Next.js dają: self-hosted fonty (CLS → 0), atrybut priority na LCP image, lazy loading third-party scripts i minimalizacja Client Components.

Nie musisz rezygnować z funkcjonalności, ale musisz ładować je w sposób logiczny i przemyślany. Pamiętaj, by sprawdzać CWV po każdej większej zmianie treści, aktualizacji czy dodaniu nowego modułu na stronie.

  • Punkt wyjścia: typowa strona usługowa1 min
  • Krok 1: Fonty — eliminacja layout shift1 min
  • Krok 2: Obrazy — next/image z priority i sizes1 min
  • Krok 3: Third-party scripts — lazy loading GTM1 min
  • Krok 4: JavaScript bundle — minimalizacja Client Components1 min
  • Krok 5: Preconnect i DNS prefetch1 min
  • Krok 6: CSS — eliminacja nieużywanych klas1 min
  • Krok 7: Animacje bez blokowania1 min
  • Wynik końcowy1 min
  • Checklist optymalizacji1 min
  • Werdykt Labu1 min

Często zadawane pytania

Źródła i data weryfikacjiZweryfikowano: 20 maja 2026

Progi Core Web Vitals, wytyczne dotyczące metryk oraz dokumentację narzędzi optymalizacyjnych zweryfikowano na podstawie oficjalnych źródeł Google i Next.js:

web.dev — Core Web Vitals, web.dev — LCP, web.dev — INP, web.dev — CLS, PageSpeed Insights, Next.js — next/image, Next.js — next/font, Next.js — next/script.

Seria

Wydajność stron w praktyce
Część 2 / 2
  1. 1Core Web Vitals — jak przyspieszyć stronę i poprawić pozycję w Google
  2. Pagespeed 100/100 w Next.js — case study optymalizacji strony usługowej
Maciej Sala

O autorze

Maciej Sala

Maciej Sala — project manager i frontendowiec z doświadczeniem w marketingu internetowym. Na co dzień pracuję z Reactem, Next.js i TypeScriptem, łącząc perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat związany z branżą gier wideo jako project manager i game designer.

Absolwent historii na Uniwersytecie Jagiellońskim i studiów podyplomowych z marketingu internetowego na Akademii Górniczo-Hutniczej w Krakowie. Poza pracą trenuje na siłowni, maluje figurki i realizuje własne projekty.

Moje artykułyWięcej o mnie

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

Umów konsultację

Biblioteka wiedzy

Czytaj dalej

Zobacz więcej wpisów
Lighthouse 100/100 w Astro — case study optymalizacji strony usługowej
Lighthouse 100/100 w Astro — case study optymalizacji strony usługowej

Jak osiągnąć 100/100 w Lighthouse dla strony Astro: optymalizacja LCP, CLS i INP przez astro:assets, Fonts API, dyrektywy client i lazy loading third-party scripts. Case study z konkretnymi metrykami.

Maciej Sala

Maciej Sala

Founder Strivelab

29 maja 2026
Core Web Vitals — jak przyspieszyć stronę i poprawić pozycję w Google
Core Web Vitals — jak przyspieszyć stronę i poprawić pozycję w Google

Core Web Vitals to kluczowe metryki wydajności i doświadczenia użytkownika. Poznaj LCP, INP i CLS oraz zobacz, jak je mierzyć, monitorować i poprawiać w praktyce.

Maciej Sala

Maciej Sala

Founder Strivelab

14 listopada 2025
Google Tag Manager w Next.js — dataLayer, custom triggers i debugowanie jak pro
Google Tag Manager w Next.js — dataLayer, custom triggers i debugowanie jak pro

Jak wdrożyć Google Tag Manager w Next.js App Router bez chaosu w dataLayer: page_view, custom events, ecommerce, consent mode i debugowanie.

Maciej Sala

Maciej Sala

Founder Strivelab

25 września 2025
Poprzedni wpisNext.js Sitemap i robots.txt — automatyczna generacja z App RouteraJak generować sitemap.xml i robots.txt w Next.js App Router? Natywne API konwencji plików vs next-sitemap — dynamiczne sitemaps, lastmod, changefreq i priorytety.
Maciej Sala

Maciej Sala

Founder Strivelab

10 kwietnia 2026
Następny wpisHreflang i canonical w Next.js — SEO wielojęzycznych stron bez duplikacjiJak poprawnie ustawić hreflang i canonical w Next.js App Router? Unikanie duplikacji treści, konfiguracja metadata API, wielojęzyczna sitemap i typowe błędy SEO.
Maciej Sala

Maciej Sala

Founder Strivelab

10 kwietnia 2026