Astro 6 Architektur: Islands, Server Islands & Content Layer API im Detail
Technischer Deep-Dive in Astro 6: Islands Architecture, Server Islands für dynamische Inhalte, die neue Content Layer API und View Transitions mit ClientRouter.
Rechtliches & Info
Die Atomic Design Methodik konsequent in Astro umsetzen: Hierarchie-Regeln, Import-Grenzen, Slot-Komposition und häufige Fallstricke beim Aufbau eines Komponentensystems.
Atomic Design ist mehr als eine Ordner-Konvention — es ist eine Denk-Architektur, die vorgibt, welche Komponente von welcher anderen abhängen darf. Brad Frosts Konzept aus 2013 ist für Astro besonders gut geeignet, weil Astro-Komponenten keine Laufzeit-Dependencies haben — Fehler in der Hierarchie fallen sofort beim Build auf, nicht erst im Browser.
Atomic Design definiert fünf Ebenen:
| Ebene | Beispiele | Importiert |
|---|---|---|
| Atoms | Button, Input, Icon, Badge, Heading | Nichts außer Design-Tokens |
| Molecules | SearchBar, FormField, NavLink, ArticleCard | Nur Atoms |
| Organisms | Header, Footer, Hero, ContactForm | Molecules (selten Atoms direkt) |
| Templates | BaseLayout, BlogLayout | Organisms |
| Pages | index.astro, blog/[slug].astro | Templates + Organisms |
Die wichtigste Regel: niemals aufwärts importieren. Ein Atom darf keine Molecule kennen. Eine Molecule darf keine Organism kennen.
src/
├── components/
│ ├── atoms/
│ │ ├── Button.astro
│ │ ├── Badge.astro
│ │ ├── Icon.astro
│ │ └── Heading.astro
│ ├── molecules/
│ │ ├── ArticleCard.astro
│ │ ├── NavLink.astro
│ │ └── PageHeader.astro
│ ├── organisms/
│ │ ├── Navigation.astro
│ │ ├── ServiceHero.astro
│ │ └── Footer.astro
│ └── seo/
│ └── SchemaArticle.astro
├── layouts/
│ └── Layout.astro
└── pages/
Ein Atom ist die kleinste wiederverwendbare Einheit. Es hat keine Knowledge über seinen Kontext — es weiß nicht, ob es in einem Header oder einem Footer gerendert wird.
---
// components/atoms/Button.astro
interface Props {
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'sm' | 'md' | 'lg';
as?: 'button' | 'a';
href?: string;
type?: 'button' | 'submit' | 'reset';
disabled?: boolean;
class?: string;
}
const {
variant = 'primary',
size = 'md',
as: Tag = 'button',
type = 'button',
disabled = false,
class: className = '',
...rest
} = Astro.props;
const variantClasses = {
primary: 'bg-primary-600 hover:bg-primary-700 text-white',
secondary: 'bg-white hover:bg-gray-50 text-primary-600 border border-primary-200',
ghost: 'bg-transparent hover:bg-gray-100 text-gray-700',
};
const sizeClasses = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-5 py-2.5 text-base',
lg: 'px-8 py-4 text-lg',
};
---
<Tag
class:list={[
'inline-flex items-center justify-center gap-2 font-semibold rounded-lg transition-colors duration-200',
variantClasses[variant],
sizeClasses[size],
disabled && 'opacity-50 cursor-not-allowed',
className,
]}
{type}
{disabled}
{...rest}
>
<slot />
</Tag>
Wichtig: Das Button-Atom importiert nichts aus dem Komponentensystem. Es kennt nur Design-Tokens über Tailwind-Klassen.
Eine Molecule kombiniert Atoms zu einer kleinen, in sich geschlossenen Einheit, die eine spezifische Funktion erfüllt.
---
// components/molecules/ArticleCard.astro
import Badge from '../atoms/Badge.astro';
interface Props {
title: string;
description: string;
slug: string;
category: string;
pubDate: Date;
readingTime: number;
categoryColor?: string;
}
const {
title,
description,
slug,
category,
pubDate,
readingTime,
categoryColor = 'bg-gray-100 text-gray-700',
} = Astro.props;
function formatDate(date: Date): string {
return date.toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' });
}
---
<article class="group bg-white dark:bg-gray-800 rounded-xl p-6 hover:shadow-md transition-shadow duration-300">
<div class="flex items-center gap-2 mb-3">
<Badge text={category} class={categoryColor} />
</div>
<h3 class="text-base font-semibold text-gray-900 dark:text-white mb-2
group-hover:text-primary-600 dark:group-hover:text-primary-400
transition-colors line-clamp-2">
<a href={`/blog/${slug}/`} class="hover:underline">{title}</a>
</h3>
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4 line-clamp-2">{description}</p>
<div class="flex items-center justify-between text-sm text-gray-500 dark:text-gray-400">
<span>{formatDate(pubDate)}</span>
<span>{readingTime} Min. Lesezeit</span>
</div>
</article>
Die ArticleCard-Molecule importiert nur Badge (ein Atom) — nicht andere Molecules oder Organisms.
---
// components/organisms/ServiceHero.astro
import Button from '../atoms/Button.astro';
import Badge from '../atoms/Badge.astro';
interface Props {
badge?: string;
title: string;
description: string;
ctaText: string;
ctaHref: string;
secondaryCtaText?: string;
secondaryCtaHref?: string;
}
const {
badge,
title,
description,
ctaText,
ctaHref,
secondaryCtaText,
secondaryCtaHref,
} = Astro.props;
---
<section class="relative py-20 md:py-32 bg-linear-to-br from-primary-50 to-white dark:from-gray-900 dark:to-gray-800 overflow-hidden">
<div class="container">
<div class="max-w-3xl mx-auto text-center">
{badge && <Badge text={badge} class="mb-6 inline-flex" />}
<h1 class="text-display-1 text-gray-900 dark:text-white mb-6">{title}</h1>
<p class="text-body-lg text-gray-600 dark:text-gray-300 mb-8">{description}</p>
<div class="flex flex-wrap items-center justify-center gap-4">
<Button as="a" href={ctaHref} variant="primary" size="lg">
{ctaText}
</Button>
{secondaryCtaText && secondaryCtaHref && (
<Button as="a" href={secondaryCtaHref} variant="secondary" size="lg">
{secondaryCtaText}
</Button>
)}
</div>
</div>
</div>
</section>
Astro-Slots sind das Haupt-Kompositions-Werkzeug. Sie ermöglichen es, Inhalte von außen in eine Komponente zu injizieren, ohne dass die Komponente den konkreten Inhalt kennen muss.
---
// components/molecules/Card.astro
---
<article class="bg-white dark:bg-gray-800 rounded-xl p-6 shadow-sm">
<header class="mb-4">
<slot name="header" />
</header>
<div class="prose prose-sm dark:prose-invert">
<slot />
</div>
{Astro.slots.has('footer') && (
<footer class="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700">
<slot name="footer" />
</footer>
)}
</article>
Nutzung:
<Card>
<Badge slot="header" text="BFSG" class="bg-purple-100 text-purple-700" />
<p>BFSG verpflichtet Unternehmen zur technischen Barrierefreiheit.</p>
<a slot="footer" href="/blog/bfsg-technische-umsetzung-astro/">Mehr erfahren</a>
</Card>
Wenn ein Organism Datenbankabfragen oder API-Calls enthält, verliert er seine Wiederverwendbarkeit. Daten gehören in die Page oder ein Layout:
---
// pages/blog/index.astro — Daten kommen von hier
import { getPublishedArticles } from '../../data/blog-articles';
import ArticleGrid from '../../components/organisms/ArticleGrid.astro';
const articles = getPublishedArticles();
---
<ArticleGrid articles={articles} />
---
// components/organisms/ArticleGrid.astro — nur Rendering, keine Daten-Logik
interface Props {
articles: BlogArticle[];
}
---
Ein Atom wie Button sollte nicht wissen, welche Routen existieren. Routen-spezifische Links gehören in Molecules oder direkt in die Page.
Kein Atom sollte Inline-Stile (style="...") oder hardcodierte Hex-Farben enthalten. Ausschließlich Design-Tokens über Tailwind-Klassen.
Wenn man ein Atom ändert — z.B. den Button-Radius vergrößert — muss sich die Änderung auf alle Molecules, Organisms und Pages auswirken, die diesen Button verwenden. Wenn das nicht passiert, hat man keine echte Atomic Design Architektur — man hat nur Ordner.
Der Test: ändere ein Atom und prüfe via grep -r "components/atoms/Button", wie viele Dateien betroffen sind. Alle diese Stellen sollten die Änderung automatisch reflektieren.
Komponentensystem für Ihr Projekt? Wender Media baut skalierbare Astro-Architekturen mit vollständiger Atomic Design Struktur — info@wendermedia.info.
Wender Media unterstützt Sie bei der praktischen Umsetzung — von der technischen Konzeption bis zum Launch. Schreiben Sie uns, wir antworten innerhalb von 24 Stunden.
Jetzt Beratung anfragenKostenlos & unverbindlich — info@wendermedia.info
Technischer Deep-Dive in Astro 6: Islands Architecture, Server Islands für dynamische Inhalte, die neue Content Layer API und View Transitions mit ClientRouter.
Was sich mit Tailwind CSS 4 wirklich ändert: CSS-first Konfiguration mit @theme, der Oxide Compiler, Container Queries, color-mix() und die Migration von v3.
TypeScript strict vollständig in Astro-Projekten nutzen: das strict-Flag, der satisfies-Operator, typsichere Props mit Generics und das Typsystem der Content Collections.