
Playwright SSG Tutorial: So machst du Lovable Apps für Google sichtbar
TL;DR: „Playwright crawlt deine SPA-Routen zur Build-Zeit und speichert vollständig gerendertes HTML als statische Dateien. Ergebnis: Google sieht alles, Lighthouse geht hoch, und du musst kein Framework wechseln."
— Till FreitagDas Problem: Google sieht deine Lovable App nicht
Du hast mit Lovable eine fantastische App gebaut. Design sitzt, Funktionalität läuft, Nutzer sind begeistert. Aber Google? Google sieht eine leere Seite.
Das liegt daran, dass Lovable – wie alle Vibe Coding Tools – Single Page Applications (SPAs) erzeugt. Der Server liefert eine leere index.html, und JavaScript rendert den Inhalt im Browser. Das funktioniert für Menschen, aber nicht für Crawlers.
Hintergrund: In unserem Vibe Coding SEO Guide erklären wir das Problem im Detail. Dieser Artikel ist der praktische Deep-Dive für die Lösung mit Playwright.
Was ist Playwright SSG?
SSG steht für Static Site Generation. Die Idee: Anstatt darauf zu hoffen, dass Googlebot JavaScript ausführt, rendern wir alle Seiten zur Build-Zeit selbst – mit einem echten Browser.
Playwright ist Microsofts Browser-Automatisierungs-Framework. Es startet einen echten Chromium-Browser, navigiert zu jeder Route deiner App, wartet bis alles gerendert ist, und speichert das fertige HTML.
Das Ergebnis:
- Jede Route hat eine vollständige HTML-Datei
- Google sieht sofort den gesamten Content
- First Contentful Paint wird dramatisch schneller
- Social Previews funktionieren sofort
Voraussetzungen
Bevor du startest, brauchst du:
- Deine Lovable App auf GitHub – Exportiere den Code über Lovable's GitHub-Integration
- Node.js 18+ auf deinem Build-System
- Grundkenntnisse in der Kommandozeile
Noch nicht auf GitHub? Unser Lovable → GitHub → Vercel Flow Guide zeigt dir den gesamten Prozess.
Schritt 1: Playwright installieren
npm install -D playwright-core @playwright/test
npx playwright install chromiumDu brauchst nur Chromium – Firefox und WebKit sind für SSG nicht nötig.
Schritt 2: Routen-Liste erstellen
Playwright muss wissen, welche Seiten es rendern soll. Du hast zwei Optionen:
Option A: Statische Route-Liste
// scripts/routes.ts
export const routes = [
'/',
'/about',
'/blog',
'/blog/mein-erster-artikel',
'/kontakt',
// ... alle deine Routen
];Option B: Automatisches Crawling
// scripts/discover-routes.ts
import { chromium } from 'playwright-core';
async function discoverRoutes(baseUrl: string): Promise<string[]> {
const browser = await chromium.launch();
const page = await browser.newPage();
const discovered = new Set<string>(['/']);
const queue = ['/'];
while (queue.length > 0) {
const route = queue.shift()!;
await page.goto(`${baseUrl}${route}`, { waitUntil: 'networkidle' });
const links = await page.$$eval('a[href]', anchors =>
anchors
.map(a => new URL(a.href, window.location.origin).pathname)
.filter(href => href.startsWith('/') && !href.includes('.'))
);
for (const link of links) {
if (!discovered.has(link)) {
discovered.add(link);
queue.push(link);
}
}
}
await browser.close();
return [...discovered];
}Wir empfehlen Option B für Websites mit vielen dynamischen Routen (z. B. Blog-Artikel).
Schritt 3: Das SSG-Script
Hier ist das Herzstück – das Script, das alle Routen rendert und als HTML speichert:
// scripts/ssg.ts
import { chromium } from 'playwright-core';
import { writeFileSync, mkdirSync } from 'fs';
import { join, dirname } from 'path';
const DIST_DIR = './dist';
const BASE_URL = 'http://localhost:4173'; // Vite preview port
async function renderRoutes(routes: string[]) {
const browser = await chromium.launch();
const context = await browser.newContext();
for (const route of routes) {
const page = await context.newPage();
await page.goto(`${BASE_URL}${route}`, {
waitUntil: 'networkidle',
timeout: 30000,
});
// Warte auf dynamische Inhalte
await page.waitForTimeout(1000);
const html = await page.content();
// Speichere als index.html im Route-Verzeichnis
const filePath = route === '/'
? join(DIST_DIR, 'index.html')
: join(DIST_DIR, route, 'index.html');
mkdirSync(dirname(filePath), { recursive: true });
writeFileSync(filePath, html, 'utf-8');
console.log(`✅ Rendered: ${route}`);
await page.close();
}
await browser.close();
console.log(`\n🎉 ${routes.length} Seiten gerendert!`);
}Schritt 4: Build-Script zusammenbauen
Füge ein ssg-Script in deine package.json ein:
{
"scripts": {
"build": "vite build",
"preview": "vite preview",
"ssg": "npm run build && npm run preview & sleep 3 && tsx scripts/ssg.ts"
}
}Was passiert:
vite builderstellt den Production Buildvite previewstartet einen lokalen Servertsx scripts/ssg.tsrendert alle Routen und überschreibt die HTML-Dateien imdist-Verzeichnis
Schritt 5: GitHub Actions CI/CD
Automatisiere den SSG-Prozess mit einer GitHub Action:
# .github/workflows/ssg.yml
name: Build & SSG
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx playwright install chromium --with-deps
- run: npm run build
# Starte Preview-Server im Hintergrund
- run: npm run preview &
- run: sleep 5
# Rendere alle Seiten
- run: npx tsx scripts/ssg.ts
# Deploy zu Vercel (oder anderem Hoster)
- uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
working-directory: ./distSchritt 6: Ergebnisse verifizieren
Nach dem ersten SSG-Build kannst du die Ergebnisse prüfen:
Lighthouse Score
npx lighthouse https://deine-domain.com --output html --output-path ./lighthouse.htmlTypische Verbesserungen:
| Metrik | Vor SSG | Nach SSG |
|---|---|---|
| First Contentful Paint | 2.8s | 0.4s |
| Largest Contentful Paint | 3.5s | 0.8s |
| Time to Interactive | 4.2s | 1.1s |
| SEO Score | 60-70 | 95-100 |
Google Search Console
Nach dem Deployment kannst du in der Google Search Console prüfen:
- URL-Prüfung → Zeigt die gerenderte Seite
- Abdeckung → Keine „Nicht indexiert"-Fehler mehr
- Core Web Vitals → Grüne Werte
Häufige Probleme und Lösungen
Problem: Dynamische Inhalte werden nicht gerendert
Lösung: Erhöhe den waitForTimeout oder warte auf spezifische Selektoren:
await page.waitForSelector('[data-loaded="true"]', { timeout: 10000 });Problem: API-Calls im Browser schlagen fehl
Lösung: Stelle sicher, dass dein Preview-Server Zugriff auf alle APIs hat. Alternativ: Mock die Daten für den SSG-Build.
Problem: Hash-Routing (#) statt Path-Routing (/)
Lösung: Lovable verwendet React Router mit Path-Routing. Falls du Hash-Routing hast, stelle auf BrowserRouter um.
Problem: Build wird zu langsam
Lösung: Parallelisiere das Rendering:
// Rendere 5 Seiten gleichzeitig
const CONCURRENCY = 5;
const chunks = [];
for (let i = 0; i < routes.length; i += CONCURRENCY) {
chunks.push(routes.slice(i, i + CONCURRENCY));
}
for (const chunk of chunks) {
await Promise.all(chunk.map(route => renderRoute(route)));
}Was noch fehlt: Schema & Meta-Tags
SSG löst das Rendering-Problem. Aber für vollständige SEO brauchst du zusätzlich:
- JSON-LD Schema für strukturierte Daten → JSON-LD Schema für SPAs automatisieren
- Meta-Tags für Social Previews (og:title, og:image, etc.)
- Sitemap und robots.txt
- Canonical URLs für mehrsprachige Inhalte
Fazit: SSG ist der Gamechanger für Vibe Coding SEO
Playwright SSG ist die fehlende Brücke zwischen Vibe Coding und Suchmaschinen. Du behältst alle Vorteile der SPA-Architektur – interaktive UI, schnelles Development, AI-generierter Code – und bekommst dazu vollständige SEO-Sichtbarkeit.
Der komplette Stack:
- Lovable → Generiert die App
- GitHub → Versioniert den Code
- Playwright → Rendert statisches HTML (dieser Artikel)
- Vercel → Liefert über Edge CDN aus
Das ist exakt der Stack, mit dem wir till-freitag.com auf Lighthouse 100 gebracht haben.
Du willst das nicht selbst aufsetzen? Wir machen das für dich →
Unser SEO-Audit zeigt dir in 48 Stunden, wo deine Vibe Coding App steht – und was nötig ist, um sie sichtbar zu machen.
Verwandte Artikel
- 📸 OG-Image Best Practices für SPAs – Pre-Rendering allein reicht nicht: So erzeugst du perfekte Social Previews für LinkedIn, Twitter und WhatsApp.
- 📊 Google Search Console für Vibe-Coding-Projekte – Wie du nach dem SSG-Setup prüfst, ob Google deine Seiten tatsächlich indexiert.








