Seed-Datei-Format

Auf dieser Seite

Seed-Dateien sind JSON-Dokumente, die EmDash-Websites initialisieren. Sie definieren Collections, Felder, Taxonomien, Menüs, Weiterleitungen, Widget-Bereiche, Website-Einstellungen und optionale Beispielinhalte.

Root-Struktur

Eine Seed-Datei hat folgende Top-Level-Struktur:

{
	"$schema": "https://emdashcms.com/seed.schema.json",
	"version": "1",
	"meta": {},
	"settings": {},
	"collections": [],
	"taxonomies": [],
	"bylines": [],
	"menus": [],
	"redirects": [],
	"widgetAreas": [],
	"sections": [],
	"content": {}
}
FeldTypErforderlichBeschreibung
$schemastringNeinJSON-Schema-URL für Editor-Validierung
version"1"JaSeed-Format-Version
metaobjectNeinMetadaten über den Seed
settingsobjectNeinWebsite-Einstellungen
collectionsarrayNeinCollection-Definitionen
taxonomiesarrayNeinTaxonomie-Definitionen
bylinesarrayNeinByline-Profil-Definitionen
menusarrayNeinNavigationsmenüs
redirectsarrayNeinWeiterleitungsregeln
widgetAreasarrayNeinWidget-Bereich-Definitionen
sectionsarrayNeinWiederverwendbare Inhaltsblöcke
contentobjectNeinBeispiel-Inhaltseinträge

Meta

Das meta-Objekt enthält optionale beschreibende Metadaten über den Seed:

{
	"meta": {
		"name": "Blog Starter",
		"description": "A simple blog with posts, pages, and categories",
		"author": "EmDash"
	}
}

Settings

Das settings-Objekt enthält websiteweite Konfigurationswerte:

{
	"settings": {
		"title": "My Site",
		"tagline": "A modern CMS",
		"postsPerPage": 10,
		"dateFormat": "MMMM d, yyyy"
	}
}

Einstellungen werden auf die options-Tabelle mit dem site:-Präfix angewendet. Der Setup-Assistent füllt title und tagline aus der Seed-Datei vor (falls vorhanden), sodass Benutzer sie während der Ersteinrichtung überschreiben können.

Collections

Jede Collection-Definition erstellt einen Content-Typ in der Datenbank:

{
	"collections": [
		{
			"slug": "posts",
			"label": "Posts",
			"labelSingular": "Post",
			"description": "Blog posts",
			"icon": "file-text",
			"supports": ["drafts", "revisions"],
			"fields": [
				{
					"slug": "title",
					"label": "Title",
					"type": "string",
					"required": true
				},
				{
					"slug": "content",
					"label": "Content",
					"type": "portableText"
				},
				{
					"slug": "featured_image",
					"label": "Featured Image",
					"type": "image"
				}
			]
		}
	]
}

Collection-Eigenschaften

EigenschaftTypErforderlichBeschreibung
slugstringJaURL-sicherer Bezeichner (Kleinbuchstaben, Unterstriche)
labelstringJaPlural-Anzeigename
labelSingularstringNeinSingular-Anzeigename
descriptionstringNeinAdmin-UI-Beschreibung
iconstringNeinLucide-Icon-Name
supportsarrayNeinFunktionen: "drafts", "revisions"
fieldsarrayJaFeld-Definitionen

Feld-Eigenschaften

EigenschaftTypErforderlichBeschreibung
slugstringJaSpaltenname (Kleinbuchstaben, Unterstriche)
labelstringJaAnzeigename
typestringJaFeldtyp
requiredbooleanNeinValidierung: Feld muss einen Wert haben
uniquebooleanNeinValidierung: Wert muss eindeutig sein
defaultValueanyNeinStandardwert für neue Einträge
validationobjectNeinZusätzliche Validierungsregeln
widgetstringNeinAdmin-UI-Widget-Überschreibung
optionsobjectNeinWidget-spezifische Konfiguration

Feldtypen

TypBeschreibungGespeichert als
stringKurzer TextTEXT
textLanger Text (Textarea)TEXT
numberNumerischer WertREAL
integerGanzzahlINTEGER
booleanWahr/FalschINTEGER
dateDatumswertTEXT (ISO 8601)
datetimeDatum und UhrzeitTEXT (ISO 8601)
emailE-Mail-AdresseTEXT
urlURLTEXT
slugURL-sicherer StringTEXT
portableTextRich-Text-InhaltJSON
imageBildreferenzJSON
fileDateireferenzJSON
jsonBeliebiges JSONJSON
referenceReferenz zu einem anderen EintragTEXT

Taxonomies

Taxonomien sind Klassifizierungssysteme für Inhalte:

{
	"taxonomies": [
		{
			"name": "category",
			"label": "Categories",
			"labelSingular": "Category",
			"hierarchical": true,
			"collections": ["posts"],
			"terms": [
				{ "slug": "news", "label": "News" },
				{ "slug": "tutorials", "label": "Tutorials" },
				{
					"slug": "advanced",
					"label": "Advanced Tutorials",
					"parent": "tutorials"
				}
			]
		},
		{
			"name": "tag",
			"label": "Tags",
			"labelSingular": "Tag",
			"hierarchical": false,
			"collections": ["posts"]
		}
	]
}

Taxonomie-Eigenschaften

EigenschaftTypErforderlichBeschreibung
namestringJaEindeutiger Bezeichner
labelstringJaPlural-Anzeigename
labelSingularstringNeinSingular-Anzeigename
hierarchicalbooleanJaVerschachtelte Begriffe erlauben (Kategorien) oder flach (Tags)
collectionsarrayJaCollections, für die diese Taxonomie gilt
termsarrayNeinVordefinierte Begriffe

Begriff-Eigenschaften

EigenschaftTypErforderlichBeschreibung
slugstringJaURL-sicherer Bezeichner
labelstringJaAnzeigename
descriptionstringNeinBegriff-Beschreibung
parentstringNeinÜbergeordneter Begriff-Slug (nur hierarchisch)

Das menus-Array definiert Navigationsmenüs, die vom Admin bearbeitbar sind:

{
	"menus": [
		{
			"name": "primary",
			"label": "Primary Navigation",
			"items": [
				{ "type": "custom", "label": "Home", "url": "/" },
				{ "type": "page", "ref": "about" },
				{ "type": "custom", "label": "Blog", "url": "/posts" },
				{
					"type": "custom",
					"label": "External",
					"url": "https://example.com",
					"target": "_blank"
				}
			]
		}
	]
}

Menüelement-Typen

TypBeschreibungErforderliche Felder
customBenutzerdefinierte URLurl
pageLink zu einem Seiten-Eintragref
postLink zu einem Beitrags-Eintragref
taxonomyLink zu einem Taxonomie-Archivref, collection
collectionLink zu einem Collection-Archivcollection

Menüelement-Eigenschaften

EigenschaftTypBeschreibung
typestringElementtyp (siehe oben)
labelstringAnzeigetext (auto-generiert für Seiten-/Beitrags-Refs)
urlstringBenutzerdefinierte URL (für custom-Typ)
refstringInhalts-ID im Seed (für page/post-Typen)
collectionstringCollection-Slug
targetstring"_blank" für neues Fenster
titleAttrstringHTML-Title-Attribut
cssClassesstringBenutzerdefinierte CSS-Klassen
childrenarrayVerschachtelte Menüelemente

Bylines

Byline-Profile sind getrennt von der Eigentümerschaft (author_id). Definieren Sie wiederverwendbare Byline-Identitäten einmal und referenzieren Sie sie dann in Inhaltseinträgen.

{
	"bylines": [
		{
			"id": "editorial",
			"slug": "emdash-editorial",
			"displayName": "EmDash Editorial"
		},
		{
			"id": "guest",
			"slug": "guest-contributor",
			"displayName": "Guest Contributor",
			"isGuest": true
		}
	]
}
EigenschaftTypErforderlichBeschreibung
idstringJaSeed-lokale ID, verwendet von content[].bylines
slugstringJaURL-sicherer Byline-Slug
displayNamestringJaIn Templates und APIs angezeigter Name
biostringNeinOptionale Profil-Bio
websiteUrlstringNeinOptionale Website-URL
isGuestbooleanNeinMarkiert Byline als Gast-Profil

Redirects

Das redirects-Array definiert Weiterleitungsregeln, die Legacy-URLs nach der Migration erhalten:

{
	"redirects": [
		{ "source": "/old-about", "destination": "/about" },
		{ "source": "/legacy-feed", "destination": "/rss.xml", "type": 308 },
		{
			"source": "/category/news",
			"destination": "/categories/news",
			"groupName": "migration"
		}
	]
}

Weiterleitungs-Eigenschaften

EigenschaftTypErforderlichBeschreibung
sourcestringJaQuellpfad (muss mit / beginnen)
destinationstringJaZielpfad (muss mit / beginnen)
typenumberNeinHTTP-Status: 301, 302, 307 oder 308
enabledbooleanNeinOb die Weiterleitung aktiv ist (Standard: true)
groupNamestringNeinOptionales Gruppierungslabel für Admin-Filterung/Suche

Widget Areas

Das widgetAreas-Array definiert konfigurierbare Inhaltsbereiche:

{
	"widgetAreas": [
		{
			"name": "sidebar",
			"label": "Main Sidebar",
			"description": "Appears on blog posts and pages",
			"widgets": [
				{
					"type": "component",
					"title": "Recent Posts",
					"componentId": "core:recent-posts",
					"props": { "count": 5 }
				},
				{
					"type": "menu",
					"title": "Quick Links",
					"menuName": "footer"
				},
				{
					"type": "content",
					"title": "About",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "Welcome to our site!" }]
						}
					]
				}
			]
		}
	]
}

Widget-Typen

TypBeschreibungErforderliche Felder
contentRich-Text-Inhaltcontent (Portable Text)
menuRendert ein MenümenuName
componentRegistrierte KomponentecomponentId

Eingebaute Komponenten

Komponenten-IDBeschreibung
core:recent-postsListe der neuesten Beiträge
core:categoriesKategorienliste
core:tagsTag-Cloud
core:searchSuchformular
core:archivesMonatliche Archive

Sections

Sections sind wiederverwendbare Inhaltsblöcke, die Redakteure über den /section-Slash-Befehl in Portable-Text-Felder einfügen:

{
	"sections": [
		{
			"slug": "hero-centered",
			"title": "Centered Hero",
			"description": "Full-width hero with centered heading and CTA button",
			"keywords": ["hero", "banner", "header", "landing"],
			"content": [
				{
					"_type": "block",
					"style": "h1",
					"children": [{ "_type": "span", "text": "Welcome to Our Site" }]
				},
				{
					"_type": "block",
					"children": [
						{ "_type": "span", "text": "Your compelling tagline goes here." }
					]
				}
			]
		}
	]
}

Section-Eigenschaften

EigenschaftTypErforderlichBeschreibung
slugstringJaURL-sicherer Bezeichner
titlestringJaIm Section-Picker angezeigter Anzeigename
descriptionstringNeinErklärt, wann diese Section verwendet werden soll
keywordsarrayNeinSuchbegriffe zum Finden der Section
contentarrayJaPortable-Text-Blöcke
sourcestringNein"theme" (Standard für Seeds) oder "import"

Sections aus Seed-Dateien sind mit source: "theme" markiert und können nicht aus der Admin-UI gelöscht werden. Redakteure können ihre eigenen Sections erstellen (source: "user") und beim Bearbeiten von Inhalten jeden Section-Typ einfügen.

Content

Das content-Objekt enthält Beispiel-Inhaltseinträge, organisiert nach Collection:

{
	"content": {
		"posts": [
			{
				"id": "hello-world",
				"slug": "hello-world",
				"status": "published",
				"bylines": [
					{ "byline": "editorial" },
					{ "byline": "guest", "roleLabel": "Guest essay" }
				],
				"data": {
					"title": "Hello World",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "Welcome!" }]
						}
					],
					"excerpt": "Your first post."
				},
				"taxonomies": {
					"category": ["news"],
					"tag": ["welcome", "first-post"]
				}
			}
		],
		"pages": [
			{
				"id": "about",
				"slug": "about",
				"status": "published",
				"data": {
					"title": "About Us",
					"content": [
						{
							"_type": "block",
							"style": "normal",
							"children": [{ "_type": "span", "text": "About page content." }]
						}
					]
				}
			}
		]
	}
}

Inhaltseintrag-Eigenschaften

EigenschaftTypErforderlichBeschreibung
idstringJaSeed-lokale ID für Referenzen
slugstringJaURL-Slug
statusstringNein"published" oder "draft" (Standard: "published")
dataobjectJaFeldwerte
bylinesarrayNeinGeordnete Byline-Credits (byline, optional roleLabel)
taxonomiesobjectNeinBegriff-Zuweisungen nach Taxonomie-Name

Content References

Referenzieren Sie andere Inhaltseinträge mit dem $ref:-Präfix:

{
	"data": {
		"related_posts": ["$ref:another-post", "$ref:third-post"]
	}
}

Das $ref:-Präfix löst Seed-IDs während des Seedings zu Datenbank-IDs auf.

Media References

Bilder von URLs einbinden:

{
	"data": {
		"featured_image": {
			"$media": {
				"url": "https://images.unsplash.com/photo-xxx",
				"alt": "Description of the image",
				"filename": "hero.jpg",
				"caption": "Photo by Someone"
			}
		}
	}
}

Lokale Bilder aus .emdash/media/ einbinden:

{
	"data": {
		"featured_image": {
			"$media": {
				"file": "hero.jpg",
				"alt": "Description of the image"
			}
		}
	}
}

Medien-Eigenschaften

EigenschaftTypErforderlichBeschreibung
urlstringJa*Remote-URL zum Herunterladen
filestringJa*Lokaler Dateiname in .emdash/media/
altstringNeinAlt-Text für Barrierefreiheit
filenamestringNeinDateinamen überschreiben
captionstringNeinMedien-Beschriftung

*Entweder url oder file ist erforderlich, nicht beides.

Applying Seeds Programmatically

Verwenden Sie die Seed-API für CLI-Tools oder Skripte:

import { applySeed, validateSeed } from "emdash/seed";
import seedData from "./.emdash/seed.json";

// Zuerst validieren
const validation = validateSeed(seedData);
if (!validation.valid) {
	console.error(validation.errors);
	process.exit(1);
}

// Seed anwenden
const result = await applySeed(db, seedData, {
	includeContent: true,
	onConflict: "skip",
	storage: myStorage,
	baseUrl: "http://localhost:4321",
});

console.log(result);
// {
//   collections: { created: 2, skipped: 0 },
//   fields: { created: 8, skipped: 0 },
//   taxonomies: { created: 2, terms: 5 },
//   bylines: { created: 2, skipped: 0 },
//   menus: { created: 1, items: 4 },
//   redirects: { created: 3, skipped: 0 },
//   widgetAreas: { created: 1, widgets: 3 },
//   settings: { applied: 3 },
//   content: { created: 3, skipped: 0 },
//   media: { created: 2, skipped: 0 }
// }

Apply-Optionen

OptionTypStandardBeschreibung
includeContentbooleanfalseBeispiel-Inhaltseinträge erstellen
onConflictstring"skip""skip", "update" oder "error"
mediaBasePathstringBasispfad für lokale Mediendateien
storageStorageStorage-Adapter für Medien-Uploads
baseUrlstringBasis-URL für Medien-URLs

Idempotency

Seeding kann sicher mehrmals ausgeführt werden. Konfliktverhalten nach Entitätstyp:

EntitätVerhalten
CollectionÜberspringen, wenn Slug existiert
FeldÜberspringen, wenn Collection + Slug existiert
Taxonomie-DefinitionÜberspringen, wenn Name existiert
Taxonomie-BegriffÜberspringen, wenn Name + Slug existiert
Byline-ProfilÜberspringen, wenn Slug existiert
MenüÜberspringen, wenn Name existiert
MenüelementeAlle ersetzen (Menü wird neu erstellt)
WeiterleitungÜberspringen, wenn Quelle existiert
Widget-BereichÜberspringen, wenn Name existiert
WidgetsAlle ersetzen (Bereich wird neu erstellt)
SectionÜberspringen, wenn Slug existiert
EinstellungenAktualisieren (Einstellungen sollen sich ändern)
InhaltÜberspringen, wenn Slug in Collection existiert

Validation

Seed-Dateien werden vor der Anwendung validiert:

import { validateSeed } from "emdash/seed";

const { valid, errors, warnings } = validateSeed(seedData);

if (!valid) {
	errors.forEach((e) => console.error(e));
}

warnings.forEach((w) => console.warn(w));

Die Validierung prüft:

  • Erforderliche Felder sind vorhanden
  • Slugs sind für ihren Typ gültig (Collection- und Feld-Slugs erlauben Kleinbuchstaben, Ziffern und Unterstriche; andere Slugs erlauben auch Bindestriche)
  • Feldtypen sind gültig
  • Referenzen zeigen auf vorhandene Inhalte
  • Hierarchische Begriff-Eltern existieren
  • Weiterleitungspfade sind sichere lokale URLs
  • Weiterleitungsquellen sind eindeutig
  • Keine doppelten Slugs innerhalb von Collections

CLI Commands

Die Seed-Datei unter .emdash/seed.json, package.json#emdash.seed oder seed/seed.json wird in den Build eingebunden und bei der ersten Anfrage angewendet, wenn die Datenbank leer ist. Um das Schema einer bestehenden Website (und optional deren Inhalt) als Seed-Datei zu exportieren:

# `mkdir -p` weil .emdash/ bei einem frischen Projekt möglicherweise noch nicht existiert
mkdir -p .emdash

# Das aktuelle Schema als Seed-Datei exportieren
npx emdash export-seed > .emdash/seed.json

# Mit Inhalt exportieren
npx emdash export-seed --with-content > .emdash/seed.json

Next Steps