Blog erstellen

Auf dieser Seite

Das EmDash-Blog-Template bietet eine funktionierende Astro-Website 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 Template-Code.

Voraussetzungen

Installieren Sie Node.js 22.12 oder höher und pnpm vor dem Start.

Sie benötigen ein Cloudflare-Konto nur beim Deployment der Website. Während der lokalen Entwicklung führt das Template lokale Versionen der Datenbank und des Dateispeichers auf Ihrem Computer aus.

Blog aufsetzen

Der folgende Befehl erstellt my-blog aus dem Cloudflare-Blog-Template und installiert seine Abhängigkeiten mit pnpm:

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

Der Scaffolder erstellt auch eine lokale .env-Datei mit einem EMDASH_ENCRYPTION_KEY. Die generierte .gitignore schließt .env von der Versionskontrolle aus. Wenn der Befehl meldet, dass die Abhängigkeitsinstallation 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 lokale URL, die im Terminal angezeigt wird, und dann /_emdash/admin. Schließen Sie den Setup-Bildschirm ab, wenn dies der erste Start ist. Die Seed-Daten des Templates erstellen das Inhaltsmodell und Beispielinhalte während des Setups.

Das Inhaltsmodell verstehen

Das Template definiert zwei Sammlungen in seed/seed.json:

  • 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, der in Beitragslisten und Metadaten-Fallbacks verwendet wird

EmDash fügt Systemfelder hinzu wie die stabile Inhalts-ID, den Slug, Status, Erstellungs- und Aktualisierungszeiten und die Veröffentlichungszeit. Das Template definiert auch category- und tag-Taxonomien für Beiträge sowie Autorenzeilen, 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 data-Eigenschaft als Post typisiert ist.

Den ersten Beitrag veröffentlichen

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

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

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

  4. Wählen Sie ein Featured Image aus der Medienbibliothek oder laden Sie eines hoch. Fügen Sie Alt-Text hinzu, der den Zweck des Bildes im Beitrag beschreibt.

  5. Weisen Sie im Einstellungspanel eine Autorenzeile, Kategorie und relevante Tags zu.

  6. Wählen Sie Save. Der Eintrag wird zum Entwurf und der Editor öffnet seine permanente Eintrags-URL.

  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 bereit ist.

Öffnen Sie /posts/your-post-slug auf der lokalen Website. Der Beitrag erscheint auch auf der Startseite und im Beitragsarchiv. Wenn er nicht erscheint, bestätigen Sie, dass der Editor Published anzeigt, nicht Draft oder Scheduled.

Nach der Veröffentlichung werden Bearbeitungen 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 zur Inhaltsbearbeitung erklärt Vorschauen, Zeitplanung, Revisionen und Bearbeitungssperren.

Der Sammlungsabfrage folgen

Die Startseite und das Beitragsarchiv rufen getEmDashCollection() während des Server-Renderings auf. Das Template ordnet Beiträge in der Datenbank nach dem gespeicherten published_at-Feld:

---
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. Sie verwendet published_at, den Datenbank-Feldnamen, für die Sortierung. Die zurückgegebene publishedAt-Eigenschaft ist ein JavaScript Date für die Darstellung.

Der Taxonomie-Helfer erhält post.data.id, weil Taxonomie-Zuweisungen zur stabilen Inhalts-ID gehören. Links verwenden stattdessen post.id, da dies der URL-seitige Slug ist, der vom Content Loader erzeugt wird:

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

Das aktuelle Template bündelt Tag-Abfragen mit getTermsForEntries() anstatt für jeden Beitrag einzeln abzufragen. Autorenzeilen sind bereits in post.data.bylines durch die Sammlungsabfrage 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 Rendering-Pfad, während das vollständige Template auch SEO, Autorenzeilen, Kommentare, verwandte Beiträge und Widgets verarbeitet:

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

const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.redirect("/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.redirect("/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 Editor ausgewählten Medienwert und generiert responsive Ausgabe. PortableText wandelt die gespeicherten Blockdaten in Überschriften, Absätze, Links, Bilder, Codeblöcke und die anderen unterstützten Blocktypen um.

Beide Blog-Templates setzen output: "server" in astro.config.mjs. Diese Abfragen werden ausgeführt, wenn eine Anfrage gerendert wird, sodass veröffentlichter Inhalt nicht von einer während des Builds erstellten statischen Routenliste abhängt.

Kategorien und Tags verwenden

Das Template enthält Archivrouten für jede Kategorie und jeden Tag. Eine Kategorieroute löst zuerst den Term-Slug auf und filtert dann 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.redirect("/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 verwendet dasselbe Muster mit getTerm("tag", slug) und where: { tag: term.slug }. Redakteure verwalten Begriffe und Zuweisungen im Admin; der Taxonomie-Leitfaden behandelt hierarchische Kategorien, flache Tags und benutzerdefinierte Taxonomien.

getEmDashEntry() enthält die zugewiesenen Begriffe des Beitrags, 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 des Templates 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 Ältere Beiträge-Link. Behalten Sie orderBy: { published_at: "desc" } zwischen den Seiten unverändert bei, 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

Das Template liefert bereits /rss.xml. Sein Endpunkt liest die 20 neuesten Beiträge mit getEmDashCollection(), formatiert jedes Veröffentlichungsdatum und escaped Titel und Auszug, bevor sie in XML eingefügt werden. Er liest auch den Seitentitel und Slogan aus den EmDash-Einstellungen.

Nachdem Sie den Testbeitrag veröffentlicht haben, öffnen Sie /rss.xml und suchen Sie nach seinem Titel. Wenn die Website eine absolute Produktions-URL in Feeds verwenden soll, setzen Sie Astros site-Option vor dem Deployment; der Endpunkt fällt während der lokalen Entwicklung auf den aktuellen Request-Origin zurück.

An diesem Punkt hat der Blog einen Authoring-Workflow, Runtime-Beitragsseiten, Taxonomie-Archive, Medien-Rendering und einen Feed. Fahren Sie fort mit Inhalte abfragen für Filter und Paginierung oder Medienbibliothek für Asset-Bearbeitung und Nutzungsverfolgung. Um Beiträge mit einem KI-Assistenten zu verfassen oder zu bearbeiten, folgen Sie KI-Werkzeuge.