Das Problem mit der React-SPA

Die erste Version von rypox.de war eine React Single-Page Application. Technisch funktional, aber mit Problemen, die sich mit der Zeit nicht verbesserten, sondern verschärften:

  • SEO war mangelhaft, Suchmaschinen-Crawler hatten Schwierigkeiten mit Client-Side Rendering. Trotz Workarounds wie react-helmet und Pre-Rendering blieben die Ergebnisse unbefriedigend
  • Initial Load war langsam, Das JavaScript-Bundle umfasste über 400 KB (gzipped). Für eine primär statische Website mit Blog und Unternehmensseiten war das unverhältnismäßig
  • Lighthouse-Scores waren mittelmäßig, Performance um 60-70, LCP über 3 Sekunden auf mobilen Geräten
  • Hydration-Overhead, React musste die gesamte Seite im Browser “hydrieren”, obwohl 90% des Inhalts statisch war

Die Entscheidung fiel: Wir brauchen ein Framework, das statische Inhalte als statisches HTML ausliefert und JavaScript nur dort einsetzt, wo es tatsächlich benötigt wird.

Warum Astro

Astro verfolgt einen radikal anderen Ansatz als React, Next.js oder Gatsby: Zero JavaScript by Default. Jede Seite wird zur Build-Zeit als statisches HTML gerendert. JavaScript wird nur explizit und gezielt eingebunden, als sogenannte “Islands”.

Core Principles

PrinzipBeschreibung
Zero JS by DefaultKein JavaScript im Browser, solange nicht explizit angefordert
Islands ArchitectureInteraktive Komponenten als isolierte “Inseln” in statischem HTML
UI-agnostischReact, Vue, Svelte, Solid, jedes Framework als Island verwendbar
Content FirstOptimiert für content-lastige Websites: Blogs, Docs, Marketing
Edge-ReadyStatic Output oder Server-Side Rendering, deploybar auf jeder Plattform

Der Unterschied in Zahlen

MetrikReact-SPA (vorher)Astro (nachher)
JS Bundle Size~420 KB (gzipped)~12 KB (nur Islands)
Initial Load (3G)~4.2s~0.8s
Lighthouse Performance62100
Lighthouse SEO78100
Lighthouse Accessibility85100
Time to Interactive~3.8s~0.9s
Build Time~45s~3s

Content Collections für den Blog

Astros Content Collections sind der Grund, warum diesen Blog überhaupt zu pflegen Spaß macht. Markdown-Dateien mit Frontmatter werden typsicher verwaltet, inklusive Schema-Validierung:

// src/content/config.ts
import { defineCollection, z } from 'astro:content';

const blogCollection = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    description: z.string(),
    date: z.date(),
    author: z.string(),
    tags: z.array(z.string()),
    image: z.string().optional(),
  }),
});

export const collections = {
  blog: blogCollection,
};

Jeder Blogartikel wird beim Build gegen dieses Schema validiert. Ein fehlender Titel oder ein falsches Datumsformat führt zu einem Build-Fehler, nicht zu einer kaputten Seite in Produktion.

Querying

---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';

const posts = (await getCollection('blog'))
  .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
---

<ul>
  {posts.map(post => (
    <li>
      <a href={`/blog/${post.slug}/`}>
        <h2>{post.data.title}</h2>
        <time>{post.data.date.toLocaleDateString('de-DE')}</time>
      </a>
    </li>
  ))}
</ul>

Kein GraphQL, kein CMS-API-Call, keine Laufzeit-Datenbank. Markdown-Dateien im Repository, typsicher gequeried zur Build-Zeit.

Islands Architecture, React als Insel

Nicht alles auf rypox.de ist statisch. Die TechSphere-Visualisierung auf der Startseite ist eine WebGL-Komponente, gebaut mit React Three Fiber. In Astro wird sie als Island eingebunden:

---
import TechSphere from '../components/TechSphere';
---

<section class="hero">
  <h1>Softwarearchitektur für den Finanzsektor</h1>
  <TechSphere client:visible />
</section>

client:visible bedeutet: Die React-Komponente wird erst geladen und hydriert, wenn sie in den Viewport scrollt. Vorher wird kein Byte JavaScript für diese Komponente übertragen.

Hydration-Strategien

DirectiveVerhaltenUse Case
client:loadSofort beim SeitenaufrufKritische interaktive Elemente
client:idleNach dem Laden, wenn Browser idleNicht-kritische Interaktivität
client:visibleWenn Komponente in Viewport scrolltBelow-the-fold Inhalte
client:mediaWenn Media Query zutrifftResponsive Interaktivität
client:onlyNur Client-Side, kein SSRReine Client-Komponenten (z.B. WebGL)

Für die TechSphere verwenden wir client:visible, weil die 3D-Visualisierung auf der Startseite erst relevant wird, wenn der Nutzer sie sieht. Das spart bei Mobile-Nutzern, die nicht bis zur Visualisierung scrollen, den kompletten Download des Three.js-Bundles. Dummerweise wird sie bei uns gleich am Anfang der Seite eingesetzt. Im konkreten Fall wird sie also doch sofort geladen, aber in der Theorie stimmt es.

Build Performance

Astro baut schnell. Die gesamte rypox.de Website, Blog, Unternehmensseiten, Komponenten, baut in unter 3 Sekunden. Das klingt trivial, hat aber praktische Auswirkungen:

  • Schnelles Feedback, Änderungen am Blog sind in Sekunden live in der Preview
  • CI/CD, Der Build-Schritt in der Pipeline ist vernachlässigbar
  • Content-Workflow, Autoren können Markdown-Dateien pushen und sehen das Ergebnis fast sofort

Vite als Build Tool

Astro nutzt Vite unter der Haube. Hot Module Replacement im Dev-Server ist quasi instantan. Das ist ein drastischer Unterschied zu Webpack-basierten React-Setups, wo nach jeder Änderung Sekunden vergehen.

llms.txt für KI-Discoverability

Ein Nebeneffekt der Migration, der sich als strategisch relevant herausgestellt hat: Astro macht es einfach, maschinenlesbare Metadaten bereitzustellen. Wir haben eine llms.txt-Datei implementiert, ein aufkommendes Format, das KI-Systemen strukturierte Informationen über eine Website bereitstellt.

# rypox GmbH
> Softwarearchitektur und Entwicklung für den Finanzsektor

## Kernkompetenzen
- Zahlungsverkehr (VoP, SEPA, ISO 20022)
- Clean Architecture und Domain-Driven Design
- Microservices mit Spring Boot und Kubernetes

## Blog
- /blog/verification-of-payee/
- /blog/kafka-echtzeit-transaktionen/
- /blog/java-21-virtual-threads/

In einer Welt, in der immer mehr Informationen über KI-Assistenten abgerufen werden, ist die maschinenlesbare Aufbereitung der eigenen Inhalte keine Spielerei, sondern vorausschauende Content-Strategie.

Deployment

Das Deployment ist denkbar einfach: Astro generiert statische HTML-Dateien, die auf jedem Webserver laufen. In unserem Fall deployen wir auf einen einfachen Nginx, kein Node.js-Server, kein CDN-Setup notwendig (auch wenn ein CDN natürlich sinnvoll ist).

npm run build    # Generiert dist/
# dist/ enthält reines HTML, CSS und minimales JS

Was wir vermissen

Fairness halber: Astro ist nicht perfekt für jeden Anwendungsfall.

  • Keine Client-Side Navigation, Jeder Seitenaufruf ist ein vollständiger Page Load. Für eine Content-Website akzeptabel, für eine Web-App nicht
  • Ökosystem kleiner als React/Next.js, Weniger Third-Party-Komponenten und Tutorials
  • View Transitions noch in Entwicklung, Astros View Transitions API verbessert sich, erreicht aber nicht die Flüssigkeit einer SPA-Navigation

Für rypox.de, eine Unternehmenswebsite mit Blog und technischen Inhalten, überwiegen die Vorteile bei weitem.

Fazit

Die Migration von React-SPA zu Astro war eine der besten technischen Entscheidungen für rypox.de. Perfekte Lighthouse-Scores, minimales JavaScript, schnelle Builds und ein Content-Workflow, der auf Markdown und Git basiert. Astro löst genau das Problem, das wir hatten: Eine Website, die primär Inhalte ausliefert, braucht kein 400-KB-JavaScript-Framework. Sie braucht gutes HTML und gezieltes JavaScript dort, wo es tatsächlich Interaktion gibt.