EmDash fügt einer Astro-Site eine Admin-Anwendung, datenbankgestützte Sammlungen, Medien, Menüs, Taxonomien, Einstellungen, Revisionen und Vorschauen hinzu. Seiten und Komponenten bleiben gewöhnliche Astro-Dateien.
Was EmDash hinzufügt
| Funktion | Was sie bietet |
|---|---|
| Admin | Browserbasierte Verwaltung von Sammlungen, Medien, Menüs, Taxonomien und Einstellungen unter /_emdash/admin |
| Datenbanksammlungen | Von Redakteuren verwaltete Inhalte, die zur Anfragezeit abgefragt werden |
| Medienbibliothek | Gespeicherte Bilder und Dateien mit Medienfeldwerten für Templates |
| Entwürfe, Revisionen und Vorschauen | Redaktionelle Arbeit vor der Veröffentlichung |
| Menüs und Widget-Bereiche | Geordnete, bearbeitbare Bereiche der Site außerhalb der Eintragsfelder |
| Site-Einstellungen | Gemeinsame Identitäts- und Anzeigewerte wie Titel, Tagline, Logo und Seitengröße der Paginierung |
| Plugins | Hooks, Routen, Speicher und optionale Admin-Erweiterungen |
Diese Funktionen existieren neben Astro und ersetzen es nicht. Astro steuert weiterhin Routing, Layouts, Rendering, Stile und den Deployment-Adapter.
EmDash und Astro-Sammlungen
Astro-Content-Collections und EmDash-Sammlungen können nebeneinander bestehen. Verwenden Sie Astro-Sammlungen für Inhalte, die dem Repository gehören, und EmDash für Inhalte, die über /_emdash/admin verwaltet werden.
| Astro-Content-Collection | EmDash-Sammlung | |
|---|---|---|
| Speicher | Dateien im Projekt | SQL-Datenbank |
| Bearbeitung | Repository-Workflow | EmDash-Admin |
| Abfrage | getCollection() | getEmDashCollection() |
| Rich Text | Markdown oder MDX | Portable Text |
| Auslieferung | Build-Zeit oder Live-Loader | Laufzeit-Live-Loader |
Verwenden Sie beide Sammlungssysteme, wenn die Zuständigkeit unterschiedlich ist. Eine Produkt-Site kann zum Beispiel von Entwicklern verfasste Release Notes in einer Astro-Content-Collection und von Redakteuren verfasste Artikel in EmDash halten:
---
import { getCollection } from "astro:content";
import { getEmDashCollection } from "emdash";
const [releaseNotes, { entries: articles }] = await Promise.all([
getCollection("releases"),
getEmDashCollection("articles", { limit: 3 }),
]);
---
Die beiden Ergebnisse bleiben getrennt. EmDash kopiert dateibasierte Einträge nicht in seine Datenbank.
Eine Site konfigurieren
Die aktuellen Node-Templates konfigurieren Astro für Server-Ausgabe, fügen die EmDash-Integration hinzu und verwenden die Adapter für SQLite und lokalen Speicher.
Die folgende reduzierte Konfiguration enthält diese erforderlichen Bestandteile:
import node from "@astrojs/node";
import react from "@astrojs/react";
import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";
export default defineConfig({
output: "server",
adapter: node({ mode: "standalone" }),
integrations: [
react(),
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
}),
],
});
EmDash liefert außerdem Cloudflare-Templates, die für D1 und R2 konfiguriert sind. Beginnen Sie mit dem Template für das Deployment-Ziel, anstatt die Node-Adapter von Hand zu übertragen.
Die Live-Sammlung registrieren
Die Templates stellen EmDash-Inhalte über eine einzige Astro-Live-Collection namens _emdash bereit:
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({ loader: emdashLoader() }),
};
getEmDashCollection() und getEmDashEntry() wählen über diesen Loader den angeforderten Inhaltstyp aus.
Sammlungen abfragen
Die folgende Abfrage liest die zuletzt veröffentlichten Beiträge. orderBy verwendet gespeicherte Feldnamen und ordnet jedem Namen "asc" oder "desc" zu:
---
import { getEmDashCollection } from "emdash";
const { entries: posts, error, cacheHint } = await getEmDashCollection("posts", {
orderBy: { published_at: "desc" },
limit: 10,
});
if (error) return new Response("Could not load posts", { status: 500 });
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---
{posts.map((post) => (
<article>
<h2><a href={`/posts/${post.id}`}>{post.data.title}</a></h2>
</article>
))}
Anonyme Abfragen liefern veröffentlichte Inhalte. Ein expliziter status-Filter ist in authentifiziertem oder vorschaufähigem Code nützlich. where akzeptiert Inhaltsfelder und Taxonomienamen; die vollständigen Formen für Filter und Paginierung finden Sie unter Inhalte abfragen.
Einen Eintrag abfragen
Übergeben Sie einen Slug oder eine Datenbank-ID an getEmDashEntry(). Die folgende Route verwendet ihren URL-Slug:
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { 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("Could not load the post", { status: 500 });
if (!post) return Astro.rewrite("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
Die zurückgegebene entry.id ist der Routing-Bezeichner von Astro und normalerweise der Slug. Die Inhalts-ID der Datenbank ist entry.data.id. Verwenden Sie data.id mit Hilfsfunktionen, die eine gespeicherte Inhalts-ID benötigen.
Dynamische CMS-Funktionen verwenden
EmDash exportiert Server-Hilfsfunktionen für Daten, die nicht zu einem einzelnen Sammlungseintrag gehören:
---
import { getMenu, getSiteSettings } from "emdash";
import { WidgetArea } from "emdash/ui";
const [menu, settings] = await Promise.all([
getMenu("primary"),
getSiteSettings(),
]);
---
<header>
<a href="/">{settings.title}</a>
<nav>
{menu?.items.map((item) => <a href={item.url}>{item.label}</a>)}
</nav>
</header>
<main><slot /></main>
<aside><WidgetArea name="sidebar" /></aside>
Ein Plugin-Format wählen
Sandbox-Plugins und native Plugins haben unterschiedliche Paketstrukturen. Sandbox-Plugins verwenden emdash-plugin.jsonc plus ein als Default exportiertes src/plugin.ts-Objekt. Native Plugins exportieren eine Descriptor-Factory und ein mit definePlugin() erstelltes createPlugin().
Lesen Sie Ein Plugin-Format wählen, bevor Sie ein Plugin hinzufügen. Kopieren Sie kein natives definePlugin()-Beispiel in ein Sandbox-Paket.