Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Performance Benchmarks w Next.js 15 - SSR vs SSG vs ISR

W Metropolii Quantum roku 2150 wydajnosc systemow to kwestia przetrwania. Kazda milisekunda opoznienia moze oznaczac utrate danych w kwantowej sieci lub awarie krytycznych systemow. Dlatego inzynierowie Metropolii musza dokladnie rozumiec roznice wydajnosciowe miedzy strategiami renderowania w Next.js 15 i umiec wybrac optymalne rozwiazanie dla kazdego przypadku.

Czym sa benchmarki wydajnosci?

Benchmarki to pomiary wydajnosci aplikacji w kontrolowanych warunkach. Pozwalaja porownac rozne strategie renderowania pod katem kluczowych metryk, takich jak:

  • TTFB (Time to First Byte) - czas od wyslania zadania do otrzymania pierwszego bajtu odpowiedzi
  • FCP (First Contentful Paint) - czas do wyrenderowania pierwszej tresci na ekranie
  • LCP (Largest Contentful Paint) - czas do wyrenderowania najwiekszego elementu w widoku
  • TTI (Time to Interactive) - czas do pelnej interaktywnosci strony
  • CLS (Cumulative Layout Shift) - stabilnosc wizualna strony podczas ladowania

Porownanie strategii renderowania

SSG (Static Site Generation) - najszybsza opcja

SSG generuje strony w czasie budowania aplikacji. Wynikowe pliki HTML sa serwowane bezposrednio z CDN, co zapewnia najnizsze mozliwe opoznienia.

1// app/blog/[slug]/page.tsx - SSG w Next.js 15
2import { notFound } from 'next/navigation';
3
4// Generowanie statycznych sciezek w czasie budowania
5export async function generateStaticParams() {
6  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
7  return posts.map((post: { slug: string }) => ({ slug: post.slug }));
8}
9
10// Domyslne cachowanie = SSG
11async function getPost(slug: string) {
12  const res = await fetch(\`https://api.example.com/posts/\${slug}\`);
13  if (!res.ok) return null;
14  return res.json();
15}
16
17export default async function BlogPost({ params }: { params: Promise<{ slug: string }> }) {
18  const post = await getPost((await params).slug);
19  if (!post) notFound();
20
21  return (
22    <article>
23      <h1>{post.title}</h1>
24      <p>{post.content}</p>
25    </article>
26  );
27}

Typowe metryki SSG:

| Metryka | Wartosc | Ocena | |---------|---------|-------| | TTFB | 5-50ms | Doskonala | | FCP | 100-300ms | Doskonala | | LCP | 200-500ms | Doskonala | | TTI | 300-800ms | Bardzo dobra | | CLS | 0-0.05 | Doskonala |

SSR (Server-Side Rendering) - dynamiczna zawartosc

SSR renderuje strony na serwerze przy kazdym zadaniu. Jest wolniejsze niz SSG, ale zapewnia zawsze aktualne dane.

1// app/dashboard/page.tsx - SSR w Next.js 15
2import { cookies } from 'next/headers';
3
4// Wymuszenie dynamicznego renderowania
5export const dynamic = 'force-dynamic';
6
7async function getDashboardData(token: string) {
8  const res = await fetch('https://api.example.com/dashboard', {
9    headers: { Authorization: \`Bearer \${token}\` },
10    cache: 'no-store', // Brak cachowania = SSR
11  });
12  return res.json();
13}
14
15export default async function Dashboard() {
16  const cookieStore = await cookies();
17  const token = cookieStore.get('auth-token')?.value || '';
18  const data = await getDashboardData(token);
19
20  return (
21    <div>
22      <h1>Panel uzytkownika</h1>
23      <p>Saldo: {data.balance} QC</p>
24      <p>Ostatnia aktywnosc: {data.lastActivity}</p>
25    </div>
26  );
27}

Typowe metryki SSR:

| Metryka | Wartosc | Ocena | |---------|---------|-------| | TTFB | 100-500ms | Srednia | | FCP | 300-800ms | Dobra | | LCP | 500-1200ms | Srednia | | TTI | 500-1500ms | Srednia | | CLS | 0-0.1 | Dobra |

ISR (Incremental Static Regeneration) - kompromis

ISR laczy zalety SSG (szybkosc) z SSR (aktualnosc danych). Strony sa generowane statycznie, ale odswiezane w tle po uplywie okreslonego czasu.

1// app/products/page.tsx - ISR w Next.js 15
2async function getProducts() {
3  const res = await fetch('https://api.example.com/products', {
4    next: { revalidate: 60 }, // Rewalidacja co 60 sekund
5  });
6  return res.json();
7}
8
9export default async function ProductsPage() {
10  const products = await getProducts();
11
12  return (
13    <div>
14      <h1>Produkty Quantum Store</h1>
15      <div className="grid">
16        {products.map((product: any) => (
17          <div key={product.id}>
18            <h2>{product.name}</h2>
19            <p>Cena: {product.price} QC</p>
20          </div>
21        ))}
22      </div>
23    </div>
24  );
25}

Typowe metryki ISR:

| Metryka | Wartosc (cache hit) | Wartosc (rewalidacja) | Ocena | |---------|--------------------|-----------------------|-------| | TTFB | 5-50ms | 100-400ms | Bardzo dobra | | FCP | 100-300ms | 300-700ms | Bardzo dobra | | LCP | 200-500ms | 500-1000ms | Dobra | | TTI | 300-800ms | 500-1200ms | Dobra | | CLS | 0-0.05 | 0-0.05 | Doskonala |

On-Demand Revalidation w Next.js 15

Next.js 15 wprowadza udoskonalona rewalidacje na zadanie, ktora pozwala odswiezyc cache bez czekania na uplyniecie czasu rewalidacji:

1// app/api/revalidate/route.ts
2import { revalidatePath, revalidateTag } from 'next/cache';
3import { NextRequest, NextResponse } from 'next/server';
4
5export async function POST(request: NextRequest) {
6  const { path, tag, secret } = await request.json();
7
8  // Weryfikacja tokenu bezpieczenstwa
9  if (secret !== process.env.REVALIDATION_SECRET) {
10    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
11  }
12
13  if (tag) {
14    // Rewalidacja po tagu - odswierza wszystkie fetche z danym tagiem
15    revalidateTag(tag);
16    return NextResponse.json({ revalidated: true, tag });
17  }
18
19  if (path) {
20    // Rewalidacja sciezki - odswierza konkretna strone
21    revalidatePath(path);
22    return NextResponse.json({ revalidated: true, path });
23  }
24
25  return NextResponse.json({ error: 'Missing path or tag' }, { status: 400 });
26}
27
28// Uzycie tagow w fetch
29async function getProduct(id: string) {
30  const res = await fetch(\`https://api.example.com/products/\${id}\`, {
31    next: {
32      revalidate: 3600, // Cache na 1 godzine
33      tags: [\`product-\${id}\`, 'products'], // Tagi do rewalidacji
34    },
35  });
36  return res.json();
37}

Hybrid Rendering - mieszanie strategii

W Next.js 15 mozna laczyc rozne strategie renderowania w ramach jednej strony dzieki Partial Prerendering (PPR):

1// app/store/page.tsx - Hybrid approach
2import { Suspense } from 'react';
3
4// Statyczna czesc strony (SSG)
5function StaticHeader() {
6  return (
7    <header>
8      <h1>Quantum Store</h1>
9      <nav>
10        <a href="/products">Produkty</a>
11        <a href="/categories">Kategorie</a>
12      </nav>
13    </header>
14  );
15}
16
17// Dynamiczna czesc strony (SSR)
18async function DynamicCart() {
19  const res = await fetch('https://api.example.com/cart', { cache: 'no-store' });
20  const cart = await res.json();
21
22  return (
23    <div>
24      <h2>Twoj koszyk ({cart.items.length} produktow)</h2>
25      <p>Suma: {cart.total} QC</p>
26    </div>
27  );
28}
29
30// Strona ISR z dynamicznymi elementami
31async function ProductList() {
32  const res = await fetch('https://api.example.com/featured', {
33    next: { revalidate: 300 },
34  });
35  const products = await res.json();
36
37  return (
38    <div>
39      {products.map((p: any) => (
40        <div key={p.id}>{p.name} - {p.price} QC</div>
41      ))}
42    </div>
43  );
44}
45
46export default function StorePage() {
47  return (
48    <div>
49      <StaticHeader />
50      <Suspense fallback={<p>Ladowanie koszyka...</p>}>
51        <DynamicCart />
52      </Suspense>
53      <Suspense fallback={<p>Ladowanie produktow...</p>}>
54        <ProductList />
55      </Suspense>
56    </div>
57  );
58}

Jak mierzyc wydajnosc w Next.js 15?

Web Vitals Reporting

1// app/layout.tsx
2import { SpeedInsights } from '@vercel/speed-insights/next';
3import { Analytics } from '@vercel/analytics/react';
4
5export default function RootLayout({ children }: { children: React.ReactNode }) {
6  return (
7    <html lang="pl">
8      <body>
9        {children}
10        <SpeedInsights />
11        <Analytics />
12      </body>
13    </html>
14  );
15}

Wbudowany profiler Next.js

1# Budowanie z profilowaniem
2NEXT_TELEMETRY_DEBUG=1 next build
3
4# Analiza rozmiaru bundla
5ANALYZE=true next build

Kiedy uzyc ktorej strategii?

| Scenariusz | Strategia | Dlaczego? | |------------|-----------|-----------| | Blog, dokumentacja | SSG | Tresci sie nie zmieniaja czesto | | E-commerce (lista produktow) | ISR (60-300s) | Produkty sie zmieniaja, ale nie co sekunde | | Dashboard uzytkownika | SSR | Dane musza byc zawsze aktualne | | Strona glowna z promocjami | ISR (300-3600s) | Promocje zmieniaja sie co kilka godzin | | Panel administracyjny | SSR | Wymaga aktualnych danych i autoryzacji | | Landing page | SSG | Maksymalna szybkosc, statyczna tresc | | Feed spolecznosciowy | SSR + Streaming | Dynamiczne dane, progresywne ladowanie |

Podsumowanie

Wybor strategii renderowania w Next.js 15 powinien byc podyktowany konkretnymi wymaganiami projektu:

  1. SSG - najszybsza opcja, idealna dla statycznych tresci
  2. ISR - kompromis miedzy szybkoscia a aktualnosciom danych
  3. SSR - pelna dynamicznosc kosztem wydajnosci
  4. Hybrid (PPR) - przyszlosc renderowania, laczacy wszystkie strategie

W Metropolii Quantum 2150 inzynierowie opieraja swoje decyzje na danych - mierza, analizuja i optymalizuja. Benchmarki wydajnosci sa kluczowym narzedziem w tym procesie.

Ir a CodeWorlds