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 es bereitstellt |
|---|---|
| Admin | Browserbasierte Verwaltung von Sammlungen, Medien, Menüs, Taxonomien und Einstellungen unter /_emdash/admin |
| Datenbank-Sammlungen | Vom Editor verwaltete Inhalte, die zur Anforderungszeit 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 Website-Bereiche außerhalb von Eintragsfeldern |
| Website-Einstellungen | Gemeinsame Identitäts- und Anzeigewerte wie Titel, Tagline, Logo und Paginierungsgröße |
| Plugins | Hooks, Routen, Speicher und optionale Admin-Erweiterungen |
Diese Funktionen existieren neben Astro, anstatt es zu ersetzen. Astro steuert weiterhin Routing, Layouts, Rendering, Styles und den Deployment-Adapter.
EmDash und Astro-Sammlungen
Astro-Content-Sammlungen und EmDash-Sammlungen können koexistieren. Verwenden Sie Astro-Sammlungen für Repository-eigene Inhalte und EmDash für Inhalte, die über /_emdash/admin verwaltet werden.
| Astro-Content-Sammlung | EmDash-Sammlung | |
|---|---|---|
| Speicherung | Dateien im Projekt | SQL-Datenbank |
| Bearbeitung | Repository-Workflow | EmDash-Admin |
| Abfrage | getCollection() | getEmDashCollection() |
| Rich Text | Markdown oder MDX | Portable Text |
| Auslieferung | Build-Time oder Live-Loader | Runtime-Live-Loader |
Verwenden Sie beide Sammlungssysteme, wenn die Verantwortung unterschiedlich ist. Beispielsweise kann eine Produktseite von Entwicklern verfasste Release Notes in einer Astro-Content-Sammlung und von Redakteuren verfasste Artikel in EmDash aufbewahren:
---
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-Output, fügen die EmDash-Integration hinzu und verwenden die SQLite- und Local-Storage-Adapter.
Die folgende reduzierte Konfiguration enthält diese erforderlichen Teile:
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 auch Cloudflare-Templates, die für D1 und R2 konfiguriert sind. Starten Sie vom Template für das Deployment-Ziel, anstatt die Node-Adapter von Hand zu übersetzen.
Die Live-Sammlung registrieren
Die Templates stellen EmDash-Inhalte über eine Astro-Live-Sammlung 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 den angeforderten Inhaltstyp über diesen Loader 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("Beiträge konnten nicht geladen werden", { 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 geben veröffentlichte Inhalte zurück. Ein expliziter status-Filter ist nützlich in authentifiziertem oder vorschaufähigem Code. where akzeptiert Inhaltsfelder und Taxonomienamen; siehe Inhalte abfragen für die vollständigen Filter- und Paginierungsformen.
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.redirect("/404");
const { entry: post, error, cacheHint } = await getEmDashEntry("posts", slug);
if (error) return new Response("Beitrag konnte nicht geladen werden", { status: 500 });
if (!post) return Astro.redirect("/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 Astros Routen-Bezeichner und ist normalerweise der Slug. Die Datenbank-Inhalts-ID ist entry.data.id. Verwenden Sie data.id mit Hilfsfunktionen, die eine gespeicherte Inhalts-ID erfordern.
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
Sandboxed und native Plugins haben unterschiedliche Paketstrukturen. Sandboxed Plugins verwenden emdash-plugin.jsonc plus ein standardmäßig exportiertes src/plugin.ts-Objekt. Native Plugins exportieren eine Deskriptor-Factory und createPlugin(), erstellt mit definePlugin().
Lesen Sie Ein Plugin-Format wählen, bevor Sie ein Plugin hinzufügen. Kopieren Sie kein natives definePlugin()-Beispiel in ein Sandboxed-Paket.