Headless Browser rendert SPA-Seiten als statisches HTML für Suchmaschinen

    Playwright SSG Tutorial: So machst du Lovable Apps für Google sichtbar

    14. April 20265 min Lesezeit
    Till Freitag

    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 Freitag

    Das 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:

    1. Deine Lovable App auf GitHub – Exportiere den Code über Lovable's GitHub-Integration
    2. Node.js 18+ auf deinem Build-System
    3. 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 chromium

    Du 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:

    1. vite build erstellt den Production Build
    2. vite preview startet einen lokalen Server
    3. tsx scripts/ssg.ts rendert alle Routen und überschreibt die HTML-Dateien im dist-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: ./dist

    Schritt 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.html

    Typische 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:

    1. URL-Prüfung → Zeigt die gerenderte Seite
    2. Abdeckung → Keine „Nicht indexiert"-Fehler mehr
    3. 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:

    1. Lovable → Generiert die App
    2. GitHub → Versioniert den Code
    3. Playwright → Rendert statisches HTML (dieser Artikel)
    4. 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

    TeilenLinkedInWhatsAppE-Mail

    Verwandte Artikel

    Prerendering-Pipeline-Visualisierung: SPA, Playwright, Schema.org und Edge-Deploy
    29. April 20263 min

    Prerendering: Wie aus einer React-SPA eine Google-freundliche Seite wird

    React-SPAs sind für Crawler unsichtbar. Prerendering löst das – ohne Next.js, ohne SSR-Server. So funktioniert unsere Pl…

    Weiterlesen
    Rakete aus Code-Elementen startet durch Suchergebnisseiten mit Lighthouse Score 100
    14. April 20265 min

    Vibe Coding & SEO: Warum KI-generierte Apps unsichtbar bleiben – und wie wir das lösen

    Lovable, Bolt, v0 – Vibe Coding Tools erzeugen SPAs, die Google nicht sieht. Unser Playbook macht sie SEO-ready: SSG, Sc…

    Weiterlesen
    Google Search Console Dashboard mit Performance-Graphen und Coverage Reports
    14. April 20264 min

    Google Search Console für Vibe-Coding-Projekte: Setup, Debugging & Indexierung

    Deine Lovable-App ist live auf Vercel – aber Google indexiert nichts? So richtest du die Search Console ein, debuggst Cr…

    Weiterlesen
    Pipeline-Diagramm mit drei Stationen: Lovable, GitHub, Vercel
    14. April 20264 min

    Lovable → GitHub → Vercel: Der komplette Deployment-Flow für SEO-ready Apps

    Lovable generiert die App, GitHub versioniert den Code, Vercel liefert mit < 50ms TTFB aus. Dieser Guide zeigt den kompl…

    Weiterlesen
    Social Media Preview Cards mit OG-Image Meta Tags schweben im dunklen Raum
    14. April 20264 min

    OG-Image Best Practices für SPAs: So werden deine Vibe-Coding-Projekte teilbar

    Wenn du einen Link aus deiner Lovable-App teilst, zeigt LinkedIn ein leeres Kästchen. Warum SPAs keine Social Previews l…

    Weiterlesen
    Lovable App mit strukturiertem HTML, sichtbar für Google, ChatGPT und Perplexity
    13. Mai 20266 min

    Lovable SEO/AEO: Jede App ab Tag 1 für Google und ChatGPT sichtbar

    Lovable bringt Server-Side-Rendering, Pre-Rendering für Bestands-Apps, Semrush direkt im Builder-Chat und einen On-Deman…

    Weiterlesen
    SaaS Analytics Dashboard mit KPI-Karten, Line Charts und Datentabellen, gebaut in Lovable
    8. März 20264 min

    SaaS Dashboard mit Lovable bauen: Vom Prompt zum fertigen Produkt

    Ein komplettes SaaS Dashboard mit Charts, Auth und Datenbank – gebaut mit Lovable in einem Nachmittag. Step-by-Step Tuto…

    Weiterlesen
    Lovable Skills: Wiederholungen werden zu wiederverwendbaren Playbooks
    19. Mai 20264 min

    Lovable Skills: Wiederholungen werden zu wiederverwendbaren Playbooks

    Lovable hat Skills ausgerollt – das Anthropic-Format für wiederverwendbare Agent-Anweisungen. Was Skills sind, wie sie s…

    Weiterlesen
    Zwei parallele Pipelines: autonome Agenten vs. Human-in-the-Loop Builder
    4. Mai 20264 min

    Purple AI (p0) vs. unser Lovable Webdev-Workflow – Autonomie vs. Human-in-the-Loop

    Purple AI (p0) verspricht autonom gemergte PRs aus einer Spec. Wir bauen Websites mit Lovable im Human-in-the-Loop-Flow.…

    Weiterlesen