Server-Side Rendering für SPAs: So verbessern Sie die Indexierung durch Suchmaschinen
Such-Crawler wie Googlebot und YandexBot erhalten bei der Analyse von CSR-basierten Single-Page-Anwendungen oft leere HTML-Seiten. Ohne Server-Side Rendering (SSR) warten sie nicht auf die Ausführung von JavaScript – und lassen Seiten daher unindexiert. SSR löst dieses Problem, indem es vollständig gerendertes HTML bereits auf dem Server generiert, bevor es an den Client gesendet wird. Dadurch beschleunigt sich FCP, LCP und TTFB – was sowohl die Core Web Vitals als auch die organische Sichtbarkeit spürbar verbessert.
Vergleich der Rendering-Methoden
| Parameter | CSR | SSR | Vorrendering | SSG |
|----------|-----|-----|--------------|-----|
| Render-Standort | Browser | Server (pro Anfrage) | Vorab für bestimmte URLs gebaut | Vorab für alle Seiten gebaut |
| FCP/LCP | Langsam | Schnell | Schnell | Sehr schnell |
| SEO | Schwach | Ausgezeichnet | Gut | Ausgezeichnet |
| Datenaktualität | Echtzeit | Echtzeit | Veraltet | Veraltet |
| Serverlast | Minimal | Hoch | Niedrig | Minimal |
SSR eignet sich besonders gut für dynamische Seiten – etwa Produktkataloge, News-Feeds oder Dashboards. Vorrendering ist ideal für selten aktualisierte URLs (z. B. Marketingseiten). SSG hingegen ist die beste Wahl für statische Inhalte wie Dokumentation oder Landingpages.
React + Next.js: Schritt-für-Schritt-Anleitung
Erstellen Sie ein neues Projekt:
npx create-next-app@latest mein-ssr-projekt
cd mein-ssr-projekt
npm run dev
Für dynamische Seiten nutzen Sie getServerSideProps:
// pages/product/[id].jsx
export async function getServerSideProps(context) {
const { id } = context.params;
const res = await fetch(`https://api.beispiel.de/produkte/${id}`);
const produkt = await res.json();
if (!res.ok) {
return { notFound: true };
}
return {
props: { produkt },
};
}
export default function ProduktSeite({ produkt }) {
return (
<main>
<h1>{produkt.name}</h1>
<p>{produkt.beschreibung}</p>
</main>
);
}
Fügen Sie suchmaschinenfreundliche Meta-Tags hinzu:
import Head from 'next/head';
export default function ProduktSeite({ produkt }) {
return (
<>
<Head>
<title>{produkt.name} | Shop</title>
<meta name="description" content={produkt.kurzbeschreibung} />
<meta property="og:title" content={produkt.name} />
<meta property="og:image" content={produkt.bildUrl} />
</Head>
<main>
<h1>{produkt.name}</h1>
</main>
</>
);
}
Deployment: Vercel, Netlify oder Node.js mit PM2.
Fehlerfreie Hydration
Hydration beschreibt, wie React im Browser das serverseitig gerenderte HTML „wiederbelebt“. Vermeiden Sie Inkompatibilitäten:
- Halten Sie Server- und Client-Daten stets synchron.
- Prüfen Sie vor der Nutzung von
windowoderdocument, ob der Code im Browser läuft. - Achten Sie auf Warnungen in der Browser-Konsole.
const istBrowser = typeof window !== 'undefined';
Vue + Nuxt.js: Server-Side Rendering
Initialisieren Sie ein Projekt:
npx nuxi@latest init mein-nuxt-projekt
cd mein-nuxt-projekt
npm install
npm run dev
Laden Sie Daten serverseitig:
<!-- pages/product/[id].vue -->
<script setup>
const route = useRoute();
const { data: produkt, error } = await useFetch(
`/api/produkte/${route.params.id}`
);
if (error.value) {
throw createError({ statusCode: 404, message: 'Nicht gefunden' });
}
useHead({
title: produkt.value?.name,
meta: [
{ name: 'description', content: produkt.value?.kurzbeschreibung },
],
});
</script>
<template>
<main>
<h1>{{ produkt?.name }}</h1>
<p>{{ produkt?.beschreibung }}</p>
</main>
</template>
Konfigurieren Sie nuxt.config.ts:
export default defineNuxtConfig({
ssr: true,
app: {
head: {
htmlAttrs: { lang: 'de' },
link: [{ rel: 'canonical', href: 'https://beispiel.de' }],
},
},
nitro: {
preset: 'node-server',
},
});
Angular Universal: SSR-Integration
Für Angular 17+:
ng add @angular/ssr
Definieren Sie den Server-Endpunkt in server.ts:
import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
// ... weitere Imports
const server = express();
// ...
server.get('*', (req, res, next) => {
commonEngine
.render({
bootstrap: AppServerModule,
documentFilePath: join(browserDistFolder, 'index.html'),
url: req.originalUrl,
publicPath: browserDistFolder,
providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }],
})
.then((html) => res.send(html))
.catch(next);
});
Bauen und starten Sie:
npm run build:ssr
npm run serve:ssr
Sichere Plattformerkennung:
import { isPlatformBrowser } from '@angular/common';
import { inject, PLATFORM_ID } from '@angular/core';
const platformId = inject(PLATFORM_ID);
if (isPlatformBrowser(platformId)) {
console.log(window.location.href);
}
Integration mit Headless CMS
Für Next.js + Contentful GraphQL:
export async function getServerSideProps({ params }) {
const query = `
query GetArtikel($slug: String!) {
artikelCollection(where: { slug: $slug }) {
items {
titel
inhalt
seo {
titel
beschreibung
}
}
}
}
`;
const res = await fetch(
`https://graphql.contentful.com/content/v1/spaces/${process.env.CONTENTFUL_SPACE_ID}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.CONTENTFUL_TOKEN}`,
},
body: JSON.stringify({ query, variables: { slug: params.slug } }),
}
);
const { data } = await res.json();
// ...
}
Wichtigste Erkenntnisse
- SSR liefert Such-Crawlern vollständig gerendertes HTML – und löst damit das zentrale Indexierungsproblem von CSR-Anwendungen.
- Next.js, Nuxt.js und Angular Universal sind erprobte Frameworks für SSR im Produktionseinsatz.
- Hydrationsfehler führen zu kompletten Neu-Renderings – prüfen Sie daher stets die Laufzeitumgebung.
- Die Core Web Vitals (FCP, LCP, TTFB) verbessern sich nach dem Wechsel zu SSR um 50–80 %.
- Nutzen Sie Redis-Caching, um die TTFB bei Traffic-Spitzen unter 200 ms zu halten.
— Editorial Team
Noch keine Kommentare.