Blog erstellen

Auf dieser Seite

Die EmDash-Blog-Vorlage liefert eine funktionsfähige Astro-Site mit Beiträgen, Seiten, Autoren, Kategorien, Tags, Suche, Kommentaren, Widgets und einem RSS-Feed. Dieses Tutorial erstellt die Cloudflare-Version, veröffentlicht einen Beitrag und verfolgt diesen Beitrag durch den Code der Vorlage.

Voraussetzungen

Installieren Sie vor dem Start Node.js 22.12 oder neuer sowie pnpm.

Ein Cloudflare-Konto benötigen Sie nur, wenn Sie die Site bereitstellen. Während der lokalen Entwicklung führt die Vorlage lokale Versionen der Datenbank und des Dateispeichers auf Ihrem Computer aus.

Blog aufsetzen

Der folgende Befehl erstellt my-blog aus der Cloudflare-Blog-Vorlage und installiert die Abhängigkeiten mit pnpm:

npm create emdash@latest my-blog -- --template cloudflare:blog --pm pnpm --yes

Der Scaffolder erstellt außerdem eine lokale .env-Datei mit einem EMDASH_ENCRYPTION_KEY. Die generierte .gitignore schließt .env von der Versionskontrolle aus. Meldet der Befehl, dass die Installation der Abhängigkeiten fehlgeschlagen ist, wechseln Sie in das Projektverzeichnis und führen Sie pnpm install aus, bevor Sie fortfahren.

Starten Sie den lokalen Entwicklungsserver:

cd my-blog
pnpm dev

Öffnen Sie die im Terminal ausgegebene lokale URL und dann /_emdash/admin. Schließen Sie den Einrichtungsbildschirm ab, falls dies der erste Start ist. Die Seed-Daten der Vorlage erstellen bei der Einrichtung das Inhaltsmodell und Beispielinhalte.

Das Inhaltsmodell verstehen

Die Vorlage definiert in seed/seed.json zwei Sammlungen:

  • posts aktiviert Entwürfe, Revisionen, Suche und SEO über supports und aktiviert Kommentare separat mit commentsEnabled: true;
  • pages unterstützt Entwürfe, Revisionen und Suche.

Jeder Beitrag hat diese benutzerdefinierten Felder:

FeldZweck
titleErforderlicher Beitragstitel
featured_imageOptionales Bild, das mit dem Beitrag angezeigt wird
contentPortable-Text-Inhalt
excerptKurztext für Beitragslisten und als Fallback für Metadaten

EmDash fügt Systemfelder hinzu, etwa die stabile Inhalts-ID, den Slug, den Status, die Erstellungs- und Aktualisierungszeit sowie die Veröffentlichungszeit. Die Vorlage definiert außerdem die Taxonomien category und tag für Beiträge sowie Bylines, die einen oder mehrere Autoren nennen können.

Der Entwicklungsserver generiert emdash-env.d.ts aus diesem Schema. Dadurch gibt getEmDashCollection("posts") Einträge zurück, deren Eigenschaft data als Post typisiert ist.

Den ersten Beitrag veröffentlichen

  1. Wählen Sie in der Admin-Seitenleiste Posts und dann Add New.

  2. Geben Sie einen Titel ein. EmDash schlägt aus dem Titel einen Slug vor; bearbeiten Sie ihn, wenn die öffentliche URL einen anderen Wert benötigt.

  3. Fügen Sie einen Auszug hinzu und schreiben Sie den Inhalt im Content-Editor.

  4. Wählen Sie ein Beitragsbild aus der Medienbibliothek aus oder laden Sie eines hoch. Fügen Sie einen Alternativtext hinzu, der den Zweck des Bildes im Beitrag beschreibt.

  5. Weisen Sie im Einstellungsbereich eine Byline, eine Kategorie und gegebenenfalls passende Tags zu.

  6. Wählen Sie Save. Der Eintrag wird zu einem Entwurf, und der Editor öffnet die dauerhafte URL des Eintrags.

  7. Wählen Sie Preview und prüfen Sie die Beitragsseite. Kehren Sie zum Editor zurück und wählen Sie Publish, wenn der Entwurf fertig ist.

Öffnen Sie /posts/your-post-slug auf der lokalen Site. Der Beitrag erscheint auch auf der Startseite und im Beitragsarchiv. Falls er nicht erscheint, vergewissern Sie sich, dass der Editor Published statt Draft oder Scheduled anzeigt.

Nach der Veröffentlichung werden Änderungen automatisch in einem neuen Entwurf gespeichert, während der aktuelle Beitrag live bleibt. Wählen Sie Publish changes, wenn der überarbeitete Entwurf ihn ersetzen soll. Der Leitfaden zum Erstellen von Inhalten erklärt Vorschauen, Zeitplanung, Revisionen und Bearbeitungssperren.

Der Sammlungsabfrage folgen

Die Startseite und das Beitragsarchiv rufen beim serverseitigen Rendern getEmDashCollection() auf. Die Vorlage sortiert die Beiträge in der Datenbank nach dem gespeicherten Feld published_at:

---
import { getEmDashCollection, getTermsForEntries } from "emdash";

const { entries: posts, cacheHint } = await getEmDashCollection("posts", {
  orderBy: { published_at: "desc" },
});

if (Astro.cache?.enabled) Astro.cache.set(cacheHint);

const tagsByEntry = await getTermsForEntries(
  "posts",
  posts.map((post) => post.data.id),
  "tag",
);
---

Die Sammlungsabfrage gibt standardmäßig veröffentlichte Einträge zurück. Für die Sortierung verwendet sie published_at, den Namen des Datenbankfelds. Die zurückgegebene Eigenschaft publishedAt ist ein JavaScript-Date zum Rendern.

Der Taxonomie-Helper erhält post.data.id, weil Taxonomiezuweisungen zur stabilen Inhalts-ID gehören. Links verwenden stattdessen post.id, denn das ist der URL-seitige Slug, den der Content-Loader erzeugt:

<a href={`/posts/${post.id}`}>
  <h2>{post.data.title}</h2>
  {post.data.excerpt && <p>{post.data.excerpt}</p>}
</a>

Die aktuelle Vorlage bündelt die Tag-Abfragen mit getTermsForEntries(), anstatt für jeden Beitrag einzeln abzufragen. Bylines sind durch die Sammlungsabfrage bereits in post.data.bylines enthalten.

Der Beitragsabfrage folgen

Die dynamische Beitragsroute liest den Slug aus der URL und ruft getEmDashEntry() auf. Der folgende Auszug zeigt den wesentlichen Abfrage- und Render-Pfad, während die vollständige Vorlage zusätzlich SEO, Bylines, Kommentare, verwandte Beiträge und Widgets behandelt:

---
import { decodeSlug, getEmDashEntry } from "emdash";
import { Image, PortableText } from "emdash/ui";

const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.rewrite("/404");

const { entry: post, error, cacheHint } = await getEmDashEntry("posts", slug);

if (error) return new Response("Unable to load post", { status: 500 });
if (!post) return Astro.rewrite("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---

<article>
  {post.data.featured_image && <Image image={post.data.featured_image} priority />}
  <h1>{post.data.title}</h1>
  <PortableText value={post.data.content} />
</article>

Image liest den vom Redakteur ausgewählten Medienwert und erzeugt eine responsive Ausgabe. PortableText wandelt die gespeicherten Blockdaten in Überschriften, Absätze, Links, Bilder, Codeblöcke und die übrigen unterstützten Blocktypen um.

Beide Blog-Vorlagen setzen in astro.config.mjs output: "server". Diese Abfragen laufen, wenn eine Anfrage gerendert wird; veröffentlichte Inhalte hängen daher nicht von einer beim Build erstellten statischen Routenliste ab.

Kategorien und Tags verwenden

Die Vorlage enthält Archivrouten für jede Kategorie und jeden Tag. Eine Kategorie-Route löst zuerst den Term-Slug auf und filtert dann die Beiträge nach dieser Taxonomie:

---
import { decodeSlug, getEmDashCollection, getTerm } from "emdash";

const slug = decodeSlug(Astro.params.slug);
const category = slug
  ? await getTerm("category", slug, { includeCounts: false })
  : null;

if (!category) return Astro.rewrite("/404");

const { entries: posts, error } = await getEmDashCollection("posts", {
  where: { category: category.slug },
  orderBy: { published_at: "desc" },
});

if (error) return new Response("Unable to load posts", { status: 500 });
---

Die tag-Route folgt demselben Muster mit getTerm("tag", slug) und where: { tag: term.slug }. Redakteure verwalten Terms und Zuweisungen im Admin; der Taxonomien-Leitfaden behandelt hierarchische Kategorien, flache Tags und benutzerdefinierte Taxonomien.

getEmDashEntry() enthält die dem Beitrag zugewiesenen Terms, sodass die Detailroute sie ohne weitere Abfrage rendern kann:

---
const categories = post.data.terms?.category ?? [];
const tags = post.data.terms?.tag ?? [];
---

{categories.map((category) => (
  <a href={`/category/${category.slug}`}>{category.label}</a>
))}
{tags.map((tag) => (
  <a href={`/tag/${tag.slug}`}>{tag.label}</a>
))}

Archiv-Paginierung hinzufügen

Das Beitragsarchiv der Vorlage rendert jeden veröffentlichten Beitrag. Wenn das Archiv wächst, fügen Sie ein limit hinzu und verwenden Sie Offset-Paginierung für nummerierte Routen wie /posts/page/2 oder Cursor-Paginierung für einen Older posts-Link. Lassen Sie orderBy: { published_at: "desc" } zwischen den Seiten unverändert, damit sich die Reihenfolge der Einträge nicht unerwartet ändert.

Die Paginierungsbeispiele zeigen beide Ansätze und erklären, wann welcher gewählt werden sollte.

Den RSS-Feed überprüfen

Die Vorlage liefert /rss.xml bereits aus. Der zugehörige Endpunkt liest mit getEmDashCollection() die 20 neuesten Beiträge, formatiert jedes Veröffentlichungsdatum und maskiert Titel und Auszug, bevor sie in das XML eingefügt werden. Außerdem liest er den Site-Titel und den Untertitel aus den EmDash-Einstellungen.

Öffnen Sie nach dem Veröffentlichen des Testbeitrags /rss.xml und suchen Sie nach seinem Titel. Wenn die Site in Feeds eine absolute Produktions-URL verwenden soll, setzen Sie vor der Bereitstellung die Astro-Option site; während der lokalen Entwicklung greift der Endpunkt auf den Origin der aktuellen Anfrage zurück.

An diesem Punkt hat der Blog einen Redaktions-Workflow, Beitragsseiten zur Laufzeit, Taxonomie-Archive, Medien-Rendering und einen Feed. Lesen Sie weiter unter Inhalte abfragen für Filter und Paginierung oder unter Medienbibliothek für die Bearbeitung von Assets und die Nutzungsverfolgung. Wie Sie Beiträge mit einem KI-Assistenten entwerfen oder bearbeiten, steht unter AI-Werkzeuge.