Das Plugin-System von EmDash ermöglicht es Ihnen, das CMS zu erweitern, ohne den Kerncode zu ändern. Plugins können sich in Content-Lifecycle-Events einhaken, eigene Daten speichern, Einstellungen für Administratoren bereitstellen und benutzerdefinierte UI zum Admin-Panel hinzufügen.
Designphilosophie
EmDash-Plugins gibt es in zwei Varianten: sandboxed und nativ. Sandboxed Plugins laufen in isolierten V8-Workern und können mit einem Klick vom Marketplace installiert werden. Native Plugins laufen im Prozess und werden im Code konfiguriert.
Bevorzugen Sie sandboxed Plugins. Sie können über die Admin-UI installiert, aktualisiert und entfernt werden, ohne Code anzufassen oder neu zu deployen. Verwenden Sie native Plugins nur, wenn Sie Funktionen benötigen, die Build-Zeit-Integration erfordern (React-Admin-Seiten, Portable Text-Rendering-Komponenten oder Page-Fragment-Injection).
Kernprinzipien:
- Sandbox-First — Entwerfen Sie für die Sandbox; verwenden Sie den nativen Modus nur bei Bedarf
- Deklarativ — Hooks, Speicher und Routen werden zur Definitionszeit deklariert, nicht dynamisch registriert
- Typsicher — Vollständige TypeScript-Unterstützung mit typisierten Kontextobjekten
- Capability-basiert — Plugins deklarieren, was sie benötigen; die Sandbox setzt es durch
Was Plugins tun können
In Events einhaken
Code vor oder nach Content-Speicherungen, Media-Uploads und Plugin-Lifecycle-Events ausführen.
Daten speichern
Plugin-spezifische Daten in indizierten Sammlungen persistieren, ohne Datenbank-Migrationen zu schreiben.
Einstellungen bereitstellen
Ein Einstellungsschema deklarieren und eine automatisch generierte Admin-UI zur Konfiguration erhalten.
Admin-Seiten hinzufügen
Benutzerdefinierte Admin-Seiten und Dashboard-Widgets mit React-Komponenten erstellen.
API-Routen erstellen
Endpoints für die Admin-UI Ihres Plugins oder externe Integrationen bereitstellen.
HTTP-Anfragen stellen
Externe APIs mit deklarierten Host-Beschränkungen zur Sicherheit aufrufen.
Plugin-Architektur
Jedes Plugin wird mit definePlugin() erstellt:
import { definePlugin } from "emdash";
export default definePlugin({
id: "my-plugin",
version: "1.0.0",
// APIs, auf die das Plugin zugreifen muss
capabilities: ["read:content", "network:fetch"],
// Hosts, an die das Plugin HTTP-Anfragen stellen kann
allowedHosts: ["api.example.com"],
// Persistente Speichersammlungen
storage: {
entries: {
indexes: ["userId", "createdAt"],
},
},
// Event-Handler
hooks: {
"content:afterSave": async (event, ctx) => {
ctx.log.info("Content saved", { id: event.content.id });
},
},
// REST-API-Endpoints
routes: {
status: {
handler: async (ctx) => ({ ok: true }),
},
},
// Admin-UI-Konfiguration
admin: {
settingsSchema: {
apiKey: { type: "secret", label: "API Key" },
},
pages: [{ path: "/dashboard", label: "Dashboard" }],
widgets: [{ id: "status", size: "half" }],
},
});
Plugin-Kontext
Jeder Hook und Route-Handler erhält ein PluginContext-Objekt mit Zugriff auf:
| Eigenschaft | Beschreibung | Verfügbarkeit |
|---|---|---|
ctx.storage | Dokumentsammlungen des Plugins | Immer (wenn deklariert) |
ctx.kv | Key-Value-Store für Einstellungen und Zustand | Immer |
ctx.content | Site-Content lesen/schreiben | Mit read:content oder write:content |
ctx.media | Mediendateien lesen/schreiben | Mit read:media oder write:media |
ctx.http | HTTP-Client für externe Anfragen | Mit network:fetch |
ctx.log | Strukturierter Logger (debug, info, warn, error) | Immer |
ctx.plugin | Plugin-Metadaten (id, version) | Immer |
ctx.site | Site-Info: name, url, locale | Immer |
ctx.url() | Absolute URLs aus Pfaden generieren | Immer |
ctx.users | Benutzerinfo lesen: get(), getByEmail(), list() | Mit read:users |
ctx.cron | Aufgaben planen: schedule(), cancel(), list() | Immer |
ctx.email | E-Mail senden: send() | Mit email:send + Provider konfiguriert |
Die Kontextform ist bei allen Hooks und Routen identisch. Capability-geschützte Eigenschaften sind nur vorhanden, wenn das Plugin die erforderliche Capability deklariert.
Capabilities
Capabilities bestimmen, welche APIs im Plugin-Kontext verfügbar sind:
| Capability | Gewährt Zugriff auf |
|---|---|
read:content | ctx.content.get(), ctx.content.list() |
write:content | ctx.content.create(), ctx.content.update(), ctx.content.delete() |
read:media | ctx.media.get(), ctx.media.list() |
write:media | ctx.media.getUploadUrl(), ctx.media.upload(), ctx.media.delete() |
network:fetch | ctx.http.fetch() (beschränkt auf allowedHosts) |
network:fetch:any | ctx.http.fetch() (unbeschränkt — für benutzerkonfigurierte URLs) |
read:users | ctx.users.get(), ctx.users.getByEmail(), ctx.users.list() |
email:send | ctx.email.send() (erfordert Provider-Plugin) |
email:provide | email:deliver exklusiven Hook registrieren (Transport-Provider) |
email:intercept | email:beforeSend / email:afterSend Hooks registrieren |
page:inject | page:metadata / page:fragments Hooks registrieren |
Registrierung
Registrieren Sie Plugins in Ihrer Astro-Konfiguration:
import { defineConfig } from "astro/config";
import { emdash } from "emdash/astro";
import seoPlugin from "@emdash-cms/plugin-seo";
import auditLogPlugin from "@emdash-cms/plugin-audit-log";
export default defineConfig({
integrations: [
emdash({
plugins: [seoPlugin({ generateSitemap: true }), auditLogPlugin({ retentionDays: 90 })],
}),
],
});
Plugins werden zur Build-Zeit aufgelöst. Die Reihenfolge ist wichtig für Hooks mit gleicher Priorität — frühere Plugins im Array laufen zuerst.
Ausführungsmodi
EmDash unterstützt zwei Plugin-Ausführungsmodi:
| Modus | Beschreibung | Plattform |
|---|---|---|
| Sandboxed | Isolierte V8-Worker mit erzwungenen Limits | Nur Cloudflare |
| Nativ | Im Prozess mit vollem Zugriff | Alle |
Im Sandbox-Modus werden Capabilities auf Runtime-Ebene durchgesetzt — Plugins können nur auf das zugreifen, was sie deklarieren. Im nativen Modus sind Capabilities beratend und Plugins haben vollen Prozesszugriff.
Nächste Schritte
Plugin erstellen
Bauen Sie Ihr erstes Plugin mit Speicher, Hooks und Admin-UI.
Verfügbare Hooks
Durchsuchen Sie alle Hooks für Content, Medien und Plugin-Lifecycle.
Plugin-Speicher
Erfahren Sie mehr über Speicher und wie Sie Plugin-Daten abfragen.
Admin-UI
Fügen Sie Admin-Seiten hinzu und Dashboard-Widgets.
Nativ vs. Sandboxed
Vergleichen Sie Ausführungsmodi und wählen Sie den richtigen für Ihr Plugin.