TL;DR: SEO dla aplikacji jednostronicowych (SPA) zaczyna się od jednej brutalnej prawdy: SPA domyślnie psują widoczność w wyszukiwarkach. Google umieszcza strony oparte na JavaScript w kolejce renderowania — a proces ten może trwać od kilku godzin do kilku dni, podczas gdy boty AI (GPTBot, ClaudeBot, PerplexityBot) w ogóle nie wykonują JavaScript. Rozwiązaniem jest SSR albo pre-rendering przez Next.js, Nuxt, Angular SSR lub SvelteKit. W tym poradniku pokazuję dokładną konfigurację dla każdego frameworka, z kodem, krokami testowymi i realiami renderowania w 2026.
Aplikacje jednostronicowe (SPA) ładują jedną powłokę HTML i wypełniają ją kodem JavaScript. Użytkownik ma szybkie wrażenie korzystania z aplikacji. Googlebot dostaje puste <div id="app"></div>.


Przeaudytowałem setki SPA przez SEOJuice. Schemat ciągle się powtarza: strona wygląda świetnie w przeglądarce, JavaScript działa idealnie, a wyszukiwarki nie widzą nic. Albo co gorsza — widzą treść dopiero po kilku dniach spędzonych w kolejce renderowania Google. Sam błąd z hash URL w Angularze kosztował klientów więcej ruchu organicznego niż jakakolwiek aktualizacja algorytmu, jaką pamiętam. Jeden klient e-commerce działający na Angularze z HashLocationStrategy miał 1,200 stron produktowych. Google widział dokładnie jedną stronę — stronę główną. Wszystko po # było niewidoczne. To nie jest subtelny spadek pozycji. To 60% ich przychodu z organicu, wyparowane przez konfigurację routingu, którą da się naprawić w dwie minuty, jeśli wiesz, gdzie patrzeć.
Tak naprawdę działa proces renderowania w Google:
Ta kolejka między krokiem 2 a krokiem 3? Może trwać od sekund do dni. Twoi konkurenci ze stronami renderowanymi po stronie serwera omijają ją całkowicie — ich treść jest indeksowana już przy pierwszym pobraniu.
Ale robi się jeszcze gorzej. W 2025 Vercel przeanalizował ponad miliard żądań od botów i odkrył, że większość botów AI w ogóle nie wykonuje JavaScript. GPTBot, ClaudeBot, PerplexityBot — pobierają i analizują wyłącznie surowy, niewyrenderowany HTML. Analiza ponad pół miliarda pobrań GPTBot nie znalazła żadnych dowodów na wykonywanie JavaScript. Jeśli Twoje SPA polega na CSR, Twoja treść jest niewidoczna dla systemów, które napędzają ChatGPT, Claude i wyszukiwarkę Perplexity.
„Jeśli Twoja strona na Next.js dostarcza kluczowe podstrony jako SPA zależne od JavaScript, te strony są niedostępne dla systemów, które kształtują sposób, w jaki ludzie odkrywają informacje.”
To nie jest niszowy problem. Jeśli chcesz, żeby Twoje treści były odkrywane zarówno przez Google, jak i boty AI w 2026, SSR albo pre-rendering nie są już opcją — to warunek konieczny.
Są cztery sposoby renderowania aplikacji typu SPA. Wybór decyduje o tym, czy wyszukiwarki zobaczą Twoją treść od razu, później, czy nigdy.
| Podejście | Jak działa | Wpływ na SEO | Czas do pierwszego bajtu (TTFB) | Najlepsze zastosowanie |
|---|---|---|---|---|
| CSR (Client-Side Rendering) | Przeglądarka pobiera pustą powłokę HTML, a JavaScript buduje stronę | Słaby — Google umieszcza stronę w kolejce renderowania, a boty AI nie widzą nic | Szybki (ale pusty) | Wewnętrzne panele, zaplecza administracyjne, strony wymagające logowania |
| SSR (Server-Side Rendering) | Serwer generuje pełny HTML dla każdego żądania i wysyła kompletną stronę | Świetny — pełna treść już przy pierwszym pobraniu | Zmienny (czas przetwarzania po stronie serwera) | Dynamiczne treści: e-commerce, serwisy newsowe, content tworzony przez użytkowników |
| SSG (Static Site Generation) | Strony są budowane podczas wdrożenia jako statyczny HTML | Świetny — najszybsze ładowanie, pełna dostępność dla robotów | Najszybszy (serwowany z CDN) | Blogi, dokumentacja, strony marketingowe, strony docelowe |
| ISR (Incremental Static Regeneration) | Statyczne strony, które regenerują się według harmonogramu albo na żądanie | Świetny — szybkość SSG z aktualną treścią | Szybki (cache z przebudową w tle) | Duże serwisy z treścią zmieniającą się okresowo (katalogi produktów, listy produktów) |
Najważniejszy wniosek
Każda strona, którą chcesz pozycjonować w Google albo botach AI, musi być renderowana po stronie serwera albo pre-renderowana. CSR jest OK dla stron po zalogowaniu i paneli. Dla wszystkiego publicznego używaj SSR, SSG albo ISR.
Zasada jest prosta: jeśli dany adres URL ma być widoczny w wynikach wyszukiwania, musi zwracać kompletny HTML już w pierwszej odpowiedzi. Bez wyjątków. Bez „ale Google przecież renderuje JavaScript”. Google renderuje — czasem, kiedyś, zawodnie, a boty AI nawet nie próbują. Tę dyskusję z frontend developerami odbywałem więcej razy, niż jestem w stanie policzyć. Zwykle kończy się w momencie, gdy pokazuję im ich stronę w URL Inspection Tool Google i widzą pustą stronę tam, gdzie powinien być ich piękny interfejs.
Czysty React (Create React App, Vite z Reactem) to tylko CSR. Google będzie mieć z tym problemy. Odpowiedzią jest Next.js — a odkąd App Router stał się domyślny w Next.js 13+, sytuacja SEO wygląda tu znacznie lepiej.
W App Router komponenty domyślnie renderują się na serwerze. Dodajesz 'use client' tylko wtedy, gdy komponent potrzebuje API przeglądarki albo interaktywności. To oznacza, że większość treści strony trafia do robota i użytkownika jako czysty HTML — bez konieczności renderowania przez JavaScript.
// app/blog/[slug]/page.tsx — Server Component (default)
import { Metadata } from 'next'
// Dynamic metadata for each blog post
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: 'article',
publishedTime: post.publishedAt,
},
alternates: {
canonical: `https://example.com/blog/${params.slug}`,
},
}
}
// This component runs on the server — zero JS shipped to the browser
export default async function BlogPost({ params }) {
const post = await getPost(params.slug)
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
)
}
Dla treści, które nie zmieniają się często (wpisy blogowe, strony docelowe), wygeneruj je wcześniej podczas procesu build:
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await getAllPosts()
return posts.map((post) => ({ slug: post.slug }))
}
// Combined with the page component above,
// Next.js generates static HTML at build time for every post
Dla sklepów e-commerce z tysiącami produktów użyj ISR, żeby odświeżać strony według harmonogramu:
// app/products/[id]/page.tsx
export const revalidate = 3600 // Regenerate every hour
export default async function ProductPage({ params }) {
const product = await getProduct(params.id)
return <ProductDetail product={product} />
}
Jeśli utknąłeś na czystym React i nie możesz przejść na Next.js, użyj usługi do pre-renderingu, takiej jak Prerender.io, jako rozwiązania tymczasowego. Ale miej świadomość, że to taśma klejąca, a nie prawdziwa naprawa. Każdy miesiąc opóźniania migracji to kolejny miesiąc gorszego indeksowania.
Ta sama historia, inny ekosystem. Czyste Vue z Vue Router to tylko CSR. Nuxt 3 daje Ci SSR, SSG, ISR i edge rendering z Nitro — wszystko w jednym frameworku.
Nuxt 3 używa universal rendering od razu po wyjęciu z pudełka. Nie trzeba nic konfigurować — Twoje strony są renderowane po stronie serwera przy pierwszym ładowaniu, a potem hydratują się do nawigacji po stronie klienta.
<!-- pages/blog/[slug].vue -->
<script setup>
const route = useRoute()
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)
// Per-page SEO metadata
useHead({
title: post.value.title,
meta: [
{ name: 'description', content: post.value.excerpt },
{ property: 'og:title', content: post.value.title },
{ property: 'og:description', content: post.value.excerpt },
],
link: [
{ rel: 'canonical', href: `https://example.com/blog/${route.params.slug}` }
]
})
</script>
<template>
<article>
<h1>{{ post.title }}</h1>
<div v-html="post.content" />
</article>
</template>
routeRules w Nuxt 3 pozwala mieszać strategie renderowania w jednej aplikacji. To bardzo mocne rozwiązanie dla serwisów, które mają jednocześnie statyczne strony marketingowe i dynamiczną treść:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // SSG — homepage
'/blog/**': { isr: 3600 }, // ISR — blog posts regenerate hourly
'/products/**': { ssr: true }, // SSR — dynamic product pages
'/dashboard/**': { ssr: false }, // CSR — authenticated dashboard
}
})
Nitro, silnik serwerowy Nuxt 3, wspiera wdrożenia na platformy edge (Cloudflare Workers, Vercel Edge, Netlify Edge). To oznacza, że Twoje strony SSR renderują się w lokalizacjach CDN najbliższych użytkownikowi — TTFB poniżej 50ms jest jak najbardziej realny. Z perspektywy SEO oznacza to szybsze ładowanie stron, lepsze Core Web Vitals i częstsze odwiedziny robotów Google.
Angular historycznie był najtrudniejszym frameworkiem do ogarnięcia pod SEO. To mocno się zmieniło od Angular 17, który zrobił z SSR obywatela pierwszej kategorii dzięki wbudowanemu wsparciu dla hydration. Koniec z doklejaniem Angular Universal jako dodatku „na później”.
Nowe projekty dostają SSR domyślnie, jeśli użyjesz CLI:
# New project with SSR enabled
ng new my-app --ssr
# Add SSR to an existing project
ng add @angular/ssr
// product-page.component.ts
import { Component, OnInit } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-product-page',
template: `
<article>
<h1>{{ product.name }}</h1>
<p>{{ product.description }}</p>
</article>
`
})
export class ProductPageComponent implements OnInit {
product: any;
constructor(
private meta: Meta,
private title: Title,
private route: ActivatedRoute,
private productService: ProductService
) {}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
this.productService.getProduct(id).subscribe(product => {
this.product = product;
this.title.setTitle(product.name);
this.meta.updateTag({ name: 'description', content: product.description });
this.meta.updateTag({ property: 'og:title', content: product.name });
});
}
}
Angular 19.2 wprowadził incremental hydration, rozwijając API @defer. Komponenty renderują pełny HTML na serwerze, ale hydratują się po stronie klienta dopiero po wyzwoleniu (po wejściu w viewport, po interakcji itd.). To zmniejsza ilość JavaScript wysyłanego do przeglądarki, a jednocześnie zostawia pełną treść SSR dostępną dla botów.
Pułapka specyficzna dla Angulara
Routing oparty na hashach (HashLocationStrategy) tworzy URL-e typu example.com/#/products. Google ignoruje wszystko po #. Twój katalog 500 produktów wygląda jak jedna strona. Przełącz się natychmiast na PathLocationStrategy — to domyślne ustawienie w Angularze, ale część starszych projektów nadal używa hash routing. To dokładnie ten błąd, który kosztował klienta e-commerce wspomnianego na początku 60% ruchu organicznego. Jechali na hash routing przez dwa lata. Dwa lata stron produktowych, o których Google nigdy się nie dowiedział. Naprawa zajęła 20 minut. Odbudowa ruchu zajęła cztery miesiące.
SvelteKit po cichu stał się jednym z najlepszych frameworków pod SEO już na starcie. SSR jest włączony domyślnie — trzeba by się naprawdę postarać, żeby go wyłączyć. Framework kompiluje framework „do zera”, wysyłając znacznie mniej JavaScript niż React czy Angular.
Każda strona SvelteKit jest domyślnie renderowana po stronie serwera. Twoje pliki +page.svelte generują kompletny HTML już przy pierwszym żądaniu:
<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
export let data;
</script>
<svelte:head>
<title>{data.post.title}</title>
<meta name="description" content={data.post.excerpt} />
<link rel="canonical" href={`https://example.com/blog/${data.post.slug}`} />
</svelte:head>
<article>
<h1>{data.post.title}</h1>
{@html data.post.content}
</article>
// src/routes/blog/[slug]/+page.server.ts
export async function load({ params }) {
const post = await getPost(params.slug);
return { post };
}
Podobnie jak Nuxt, SvelteKit pozwala kontrolować renderowanie na poziomie route'a:
// src/routes/blog/[slug]/+page.ts
export const prerender = true; // SSG — generate at build time
// src/routes/dashboard/+page.ts
export const ssr = false; // CSR-only for authenticated content
Dlaczego SvelteKit zasługuje na uwagę pod kątem SEO: kompilator eliminuje runtime frameworka. Strona na SvelteKit wysyła ułamek JavaScript, który poleciałby w równoważnej stronie na Next.js czy Nuxt. Mniej JavaScript oznacza szybszy LCP, lepsze wyniki INP i szczęśliwsze Core Web Vitals — a to wszystko są sygnały rankingowe.
Każde SPA powinno przejść te kontrole. Kolejność jest według wpływu — najpierw naprawiaj rzeczy z góry listy.
| # | Kontrola | Dlaczego to ważne | Jak naprawić |
|---|---|---|---|
| 1 | SSR albo SSG włączone dla wszystkich publicznych stron | Bez tego Google umieszcza strony w kolejce renderowania, a boty AI nie widzą nic | Next.js App Router, Nuxt 3, Angular SSR albo SvelteKit |
| 2 | Czyste URL-e (bez hash fragmentów) | Hash URL-e (#/page) są niewidoczne dla wyszukiwarek | Użyj routingu opartego na History API — domyślnego we wszystkich nowoczesnych frameworkach |
| 3 | Unikalny title tag dla każdej strony | Ten sam title na każdej ścieżce oznacza, że Google wybierze jeden i zignoruje resztę | generateMetadata (Next.js), useHead() (Nuxt), serwis Meta (Angular), <svelte:head> |
| 4 | Unikalny meta description dla każdej strony | Kontroluje snippet w wynikach wyszukiwania | Te same biblioteki co dla title tagów — ustawiaj per route |
| 5 | Canonical tagi na każdej stronie | Zapobiegają problemom z duplikacją treści przez query params i trailing slashe | Dodaj <link rel="canonical"> dla każdej strony w metadata |
| 6 | Poprawna hierarchia nagłówków (H1 > H2 > H3) | Sygnalizuje botom strukturę treści | Jeden H1 na stronę, logiczne zagnieżdżenie w komponentach |
| 7 | Linki wewnętrzne używają prawdziwych tagów <a href> | Nawigacja oparta wyłącznie na JavaScript (handlery onClick) blokuje boty | Używaj komponentów Link z frameworka: <Link>, <NuxtLink>, routerLink |
| 8 | Wysłana mapa XML sitemap | Pomaga Google odkrywać strony, do których nie da się dojść przez linki | Generuj przez next-sitemap, nuxt-simple-sitemap albo narzędzia właściwe dla frameworka |
| 9 | Code splitting i lazy loading | Zmniejszają początkowy bundle JS, poprawiają LCP i INP | Dynamic imports (next/dynamic, defineAsyncComponent, @defer) |
| 10 | Schema markup (JSON-LD) na kluczowych stronach | Włącza rich snippets i pomaga botom AI zrozumieć treść | JSON-LD w <head> albo <body> — renderowany po stronie serwera, nie wstrzykiwany przez JS |
To są błędy, które widzę w prawie każdym audycie SPA. Każdy jeden zabija widoczność.
„Ale Google renderuje JavaScript!” — tak, czasem, kiedyś, jeśli Twój JS nie rzuci błędu, jeśli kolejka renderowania nie jest zapchana, jeśli JavaScript nie przekroczy limitu czasu i jeśli żaden skrypt third-party nie rozwali renderu. Sporo tych „jeśli”, żeby stawiać na nich cały ruch organiczny. A boty AI nawet nie spróbują.
// WRONG — CSR-only React app
// Google sees: <div id="root"></div>
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
// RIGHT — Next.js Server Component
// Google sees: fully rendered HTML with all content
export default async function Page() {
const data = await fetchData();
return <Article data={data} />;
}
HashLocationStrategy w Angularze i hash mode w Vue Router produkują URL-e typu example.com/#/products/shoes. Google ignoruje wszystko po #. Cała Twoja aplikacja wygląda jak jedna strona.
// WRONG — Vue Router hash mode
const router = createRouter({
history: createWebHashHistory(), // URLs: example.com/#/about
routes
})
// RIGHT — Vue Router history mode
const router = createRouter({
history: createWebHistory(), // URLs: example.com/about
routes
})
SPA startują z jednym <title> w powłoce HTML. Jeśli nie aktualizujesz go dynamicznie dla każdej ścieżki, każda strona ma ten sam title. Google zaindeksuje jedną wersję i zignoruje resztę.
<!-- WRONG — static HTML shell with one title -->
<!DOCTYPE html>
<html>
<head>
<title>My App</title> <!-- Same for every route -->
</head>
<body><div id="app"></div></body>
</html>
<!-- RIGHT — dynamic metadata per route (Nuxt example) -->
<script setup>
useHead({
title: `${product.name} | MyStore`,
meta: [{ name: 'description', content: product.summary }]
})
</script>
Jeden nieobsłużony błąd w aplikacji może zablokować wyrenderowanie całej strony. Web Rendering Service Google nie robi retry. Strona zostaje pusta w indeksie.
Widzę to non stop: skrypt analityczny third-party rzuca błędem albo brakująca odpowiedź z API wysypuje całe drzewo komponentów. Efekt? Google indeksuje pustą stronę. Jeden klient miał snippet Hotjar, który okazjonalnie wysypywał się w rendererze Google. Ich strony produktowe losowo pokazywały się jako puste w URL Inspection Tool w GSC. Naprawa polegała na dodaniu error boundary wokół inicjalizacji analityki. Zajęło 10 minut. Po cichu szkodziło indeksowaniu przez miesiące.
Naprawa: dodaj error boundaries w React (ErrorBoundary components), używaj NuxtErrorBoundary w Nuxt i zawsze testuj stronę z wyłączonym JavaScript (więcej o tym niżej).
SPA z routingiem po stronie klienta nie pokazują swojej struktury URL-i przez linki HTML tak, jak robią to klasyczne strony wielopodstronowe. Bez sitemap Google odkrywa strony tylko przez linki dostępne dla robotów — a jeśli Twoje linkowanie wewnętrzne jest sterowane JavaScript, może nie znaleźć nic.
# Install next-sitemap for Next.js
npm install next-sitemap
# next-sitemap.config.js
module.exports = {
siteUrl: 'https://example.com',
generateRobotsTxt: true,
changefreq: 'weekly',
// Exclude routes that shouldn't be indexed
exclude: ['/dashboard/*', '/api/*', '/admin/*'],
}
Jeśli Twój robots.txt blokuje pliki CSS albo JS, renderer Google nie może zbudować strony. Zaskakująco często to widzimy — zwykle jako pozostałość po domyślnej konfiguracji.
# WRONG — blocking JS and CSS
User-agent: *
Disallow: /static/js/
Disallow: /static/css/
# RIGHT — allow all resources needed for rendering
User-agent: *
Disallow: /api/
Disallow: /dashboard/
Allow: /static/

Nie zakładaj, że Twoje SPA jest dostępne dla robotów tylko dlatego, że działa w Chrome. Tak sprawdzisz, co naprawdę widzą wyszukiwarki.
URL Inspection Tool to Twoje najlepsze pojedyncze narzędzie diagnostyczne. Wpisz dowolny URL i kliknij „Test Live URL”. Google pobierze stronę, wyrenderuje ją przez swój Web Rendering Service i pokaże wynik.
Na co patrzeć:
To najprostszy test, a zaskakująco często obnaża problem w 30 sekund. Otwórz DevTools w Chrome, przejdź do Command Menu, wpisz „Disable JavaScript” i odśwież stronę.
Jeśli po odświeżeniu widzisz pełną treść, jesteś w dobrej sytuacji — to znaczy, że strona zwraca HTML po stronie serwera albo została wcześniej wygenerowana. Jeśli widzisz pusty ekran, spinner albo sam nagłówek i nic więcej, masz problem z SEO. Dla botów AI to w zasadzie test ostateczny, bo one właśnie tak „widzą” web.
Nie patrz tylko na DOM po wykonaniu JavaScript. Sprawdź surową odpowiedź serwera:
curl -A "Googlebot" https://example.com/product-page
W odpowiedzi powinieneś zobaczyć właściwą treść strony, title, meta description, canonical i linki wewnętrzne. Jeśli dostajesz głównie pustą powłokę HTML z jednym <div id="root">, to znaczy, że nadal polegasz na CSR.
Nasze darmowe narzędzie do audytu SEO skanuje Twoje SPA pod kątem problemów z renderowaniem, brakujących meta tagów, uszkodzonych linków i problemów z dostępnością. Pokazuje dokładnie to, co widzą wyszukiwarki — bez logowania, wynik w 30 sekund.
Ponieważ boty AI nie renderują JavaScript, sprawdź, czy mają dostęp do Twojej treści przez AI Crawler Inspector. Narzędzie symuluje, jak GPTBot, ClaudeBot i inne boty AI widzą Twoje strony.
Krajobraz SEO dla SPA w 2026 wygląda zauważalnie inaczej niż jeszcze dwa lata temu. Oto co naprawdę ma znaczenie.
W Next.js App Router komponenty domyślnie renderują się na serwerze. W renderowanie po stronie klienta wchodzisz świadomie przez 'use client'. To odwraca stary model — zamiast mieć wszędzie CSR z doklejonym SSR, masz wszędzie SSR z dodanym CSR tam, gdzie jest potrzebny. Konsekwencje dla SEO są ogromne: większość aplikacji trafia do robota i użytkownika jako czysty HTML automatycznie.
Nuxt 3 z Nitro, Next.js Edge Runtime i adaptery SvelteKit pozwalają dziś wdrażać SSR na lokalizacje edge CDN (Cloudflare Workers, Vercel Edge Functions). Twoje strony renderują się na węźle edge najbliższym użytkownikowi — albo botowi. Globalny TTFB poniżej 50ms jest osiągalny.
Angular 17+ wbudował SSR do CLI przez ng new --ssr. Angular 19 dodał incremental hydration. Czasy bolesnej konfiguracji Angular Universal minęły. Jeśli nadal działasz na aplikacji Angular opartej wyłącznie na CSR, ścieżka migracji jest dziś prosta.
GPTBot, ClaudeBot, PerplexityBot i inne boty przeszukują web, żeby budować dane treningowe i zasilać wyszukiwarki AI. Żaden z nich nie wykonuje JavaScript. Analiza ponad pół miliarda żądań GPTBot nie wykazała żadnych śladów wykonywania JS. Jeśli chcesz, żeby Twoje treści były cytowane w odpowiedziach generowanych przez AI, SSR jest jedynym sposobem, żeby się tam pojawiać.
„Widzenie wyrenderowanego HTML, a nie tylko kodu źródłowego, jest ważne przy diagnozowaniu problemów z indeksowaniem. Google może odkrywać Twoje linki tylko wtedy, gdy są elementami HTML
<a>z atrybutemhref.”
LCP, INP i CLS nadal są sygnałami rankingowymi. SPA wysyłające duże bundle JavaScript dostają po głowie w LCP (strona zbyt długo pokazuje sensowną treść) i INP (interakcje są ociężałe). Code splitting, lazy loading i minimalna ilość JavaScript po stronie klienta nie są opcjonalne — to wymagania wydajnościowe, które bezpośrednio wpływają na widoczność.
„Prerendering strony statycznie albo po stronie serwera to najlepsza praktyka SEO — sprawia, że crawlery chętniej i częściej ponownie indeksują Twoją stronę.”
Nie wiesz, który framework wybrać? Tak wyglądają różnice konkretnie pod SEO.
| Funkcja | Next.js (React) | Nuxt 3 (Vue) | Angular SSR | SvelteKit |
|---|---|---|---|---|
| SSR domyślnie | Tak (App Router) | Tak | Tak (od v17) | Tak |
| Generowanie statyczne | generateStaticParams | prerender: true | ng build --prerender | export const prerender = true |
| Wsparcie dla ISR | Wbudowane (revalidate) | Wbudowane (isr: seconds) | Ręcznie przez service worker | Przez konfigurację zależną od adaptera |
| Edge rendering | Vercel Edge, Cloudflare | Nitro (wiele platform) | Ograniczone | Wiele adapterów |
| API metadata per page | generateMetadata | useHead() | Meta + serwisy Title | <svelte:head> |
| Wysyłany client JS | Umiarkowany (RSC pomaga) | Umiarkowany | Ciężki | Minimalny (kompilowany do zera) |
| Społeczność / ekosystem | Największy | Mocny | Nastawiony na enterprise | Szybko rośnie |
Tak, ale z zastrzeżeniami. Web Rendering Service Google używa przeglądarki headless Chromium do wykonywania JavaScript i renderowania SPA. Problem w tym, że renderowanie odbywa się w osobnej kolejce po początkowym pobraniu, co może opóźnić indeksację od kilku godzin do kilku dni. Strony z błędami JavaScript mogą nigdy się nie wyrenderować. Jeśli chcesz niezawodnego indeksowania, używaj SSR albo SSG — nie polegaj na kolejce renderowania Google przy treściach wrażliwych czasowo.
SPA oparte wyłącznie na CSR jest złe dla SEO. SPA z renderowaniem po stronie serwera już nie. Framework sam w sobie nie ma znaczenia — znaczenie ma to, czy początkowa odpowiedź HTML zawiera Twoją treść. Next.js, Nuxt, Angular SSR i SvelteKit potrafią generować w pełni dostępne dla robotów SPA. Problem „SPA vs SEO” został rozwiązany lata temu; problemem są developerzy, którzy nie wdrażają rozwiązania.
Dla każdej strony, która ma się pozycjonować w wyszukiwarce? Tak. Sam React (przez Vite albo Create React App) to tylko CSR — wyszukiwarki widzą pustą stronę. Next.js dodaje SSR, SSG i ISR. Dzięki React Server Components w App Router większość komponentów renderuje się domyślnie na serwerze. Jeśli Twoja aplikacja React obsługuje publiczny content, Next.js jest standardowym rozwiązaniem.
Nie radzą sobie. GPTBot (OpenAI), ClaudeBot (Anthropic), PerplexityBot i inne boty AI nie wykonują JavaScript. Parsują wyłącznie surowy HTML. Analiza ponad pół miliarda żądań GPTBot nie wykazała żadnych śladów renderowania JavaScript. Jeśli Twoja treść jest renderowana po stronie klienta, jest niewidoczna dla wyszukiwarek AI. SSR to jedyny sposób, żeby pojawiać się w odpowiedziach i cytowaniach generowanych przez AI.
SSR (Server-Side Rendering) generuje HTML przy każdym żądaniu — najlepsze dla dynamicznej treści. SSG (Static Site Generation) generuje HTML podczas build — najszybsze, ale wymaga przebudowy przy zmianach treści. ISR (Incremental Static Regeneration) generuje statyczne strony, które automatycznie regenerują się według harmonogramu — łączy szybkość SSG ze świeżością treści. Wszystkie trzy podejścia dostarczają pełny HTML wyszukiwarkom już przy pierwszym żądaniu. Wybór zależy od tego, jak często zmienia się Twoja treść.
SPA nie są z natury złe dla SEO. Ale SPA oparte wyłącznie na CSR już tak — a w 2026 są też niewidoczne dla botów AI.
Rozwiązanie jest dostępne od lat. Next.js, Nuxt 3, Angular SSR i SvelteKit wszystkie dostarczają HTML renderowany po stronie serwera od razu po wdrożeniu. React Server Components jeszcze poprawiły domyślne zachowanie — większość aplikacji renderuje się na serwerze automatycznie. Nie ma dziś sensownej wymówki, żeby wypuszczać publiczne SPA bez SSR albo pre-renderingu.
Jeśli nie masz pewności, czy Twoje SPA jest dostępne dla robotów, uruchom darmowy audyt SEO — zajmuje 30 sekund i pokazuje dokładnie to, co widzi Google. Jeśli chcesz sprawdzić widoczność dla botów AI, użyj AI Crawler Inspector.
Powiązane materiały:
no credit card required
No related articles found.