Ein blocks-Feld speichert eine geordnete Seitenkomposition. Jedes Element hält einen Blocktyp, eine beibehaltene Schema-Version, einen stabilen Schlüssel und die von dieser Version deklarierten Felder fest. Redakteure fügen Blöcke im Inhaltseditor hinzu und ordnen sie neu an. Die Astro-Route ordnet jeden Blocktyp einer Komponente zu.
Blocktypen definieren
Definieren Sie Blocktypen vor dem Collection-Feld, das sie verwendet. Ein Seed bewahrt jede nummerierte Version und den aktiven currentVersion-Zeiger.
Der folgende Seed definiert die Blöcke Hero und Feature grid und macht sie dann in einem layout-Feld der Pages-Collection verfügbar:
{
"$schema": "https://emdashcms.com/seed.schema.json",
"version": "1",
"blockTypes": [
{
"slug": "hero",
"label": "Hero",
"category": "Layout",
"currentVersion": 1,
"versions": [
{
"version": 1,
"fields": [
{ "slug": "heading", "label": "Heading", "type": "string", "required": true },
{ "slug": "body", "label": "Body", "type": "portableText" },
{ "slug": "image", "label": "Image", "type": "image" },
{ "slug": "link_label", "label": "Link label", "type": "string" },
{ "slug": "link_url", "label": "Link URL", "type": "url" }
]
}
]
},
{
"slug": "feature_grid",
"label": "Feature grid",
"category": "Layout",
"currentVersion": 1,
"versions": [
{
"version": 1,
"fields": [
{ "slug": "heading", "label": "Heading", "type": "string" },
{
"slug": "items",
"label": "Items",
"type": "repeater",
"validation": {
"subFields": [
{ "slug": "title", "label": "Title", "type": "string", "required": true },
{ "slug": "description", "label": "Description", "type": "text" }
]
}
}
]
}
]
}
],
"collections": [
{
"slug": "pages",
"label": "Pages",
"fields": [
{ "slug": "title", "label": "Title", "type": "string", "required": true },
{
"slug": "layout",
"label": "Layout",
"type": "blocks",
"validation": {
"allowedTypes": ["hero", "feature_grid"],
"maxItems": 20
}
}
]
}
]
}
Die Reihenfolge von allowedTypes steuert die Blockauswahl. Entfernen Sie später einen erlaubten Typ, verschiebt EmDash ihn in die servergesteuerte Liste retiredTypes. Vorhandene Blöcke bleiben bearbeitbar, aber Redakteure können diesen Typ nicht mehr hinzufügen oder duplizieren.
Die Astro-Komponenten erstellen
Jede Komponente erhält value, index und blockKey. Der Wert enthält _type, _version und _key, sodass eine Komponente beibehaltene Versionen eingrenzen kann, wenn sich ihr Block-Schema weiterentwickelt.
Die Hero-Komponente liest jeden angezeigten Wert aus dem gespeicherten Block:
---
import { sanitizeHref } from "emdash";
import { Image, PortableText, type BlockComponentProps } from "emdash/ui";
import type { PageLayoutBlock } from "../../../emdash-env";
type HeroBlock = Extract<PageLayoutBlock, { _type: "hero" }>;
type Props = BlockComponentProps<HeroBlock>;
const { value } = Astro.props;
---
<section class="hero">
<div>
<h1>{value.heading}</h1>
{value.body && <PortableText value={value.body} />}
{value.link_url && <a href={sanitizeHref(value.link_url)}>{value.link_label}</a>}
</div>
{value.image && <Image image={value.image} />}
</section>
Erstellen Sie für jeden erlaubten Typ eine Komponente. Die Komponente steuert Markup und Styling; der Blockwert liefert Inhalt und Medien.
Die Komposition rendern
Verwenden Sie defineBlockComponents, um für jeden _type in der generierten Feld-Union genau eine Komponente zu verlangen. Übergeben Sie diese Zuordnung in der Seitenroute an <Blocks>.
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { Blocks, defineBlockComponents } from "emdash/ui";
import type { PageLayoutBlock } from "../../../emdash-env";
import FeatureGrid from "../../components/blocks/FeatureGrid.astro";
import Hero from "../../components/blocks/Hero.astro";
const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.rewrite("/404");
const { entry: page, cacheHint } = await getEmDashEntry("pages", slug);
if (!page) return Astro.rewrite("/404");
Astro.cache.set(cacheHint);
const components = defineBlockComponents<PageLayoutBlock>({
hero: Hero,
feature_grid: FeatureGrid,
});
---
<Blocks value={page.data.layout} components={components} />
<Blocks> führt keine Inhalts-, Schema-, Medien- oder Netzwerkabfragen aus. Es rendert das übergebene Array in der gespeicherten Reihenfolge. Eine Blockkomponente kann eine explizite Anwendungsabfrage ausführen, wenn sie weitere Daten benötigt.
Mit einer fehlenden Komponente umgehen
Während der Entwicklung erzeugt ein nicht zugeordneter Typ einen sichtbaren Platzhalter und eine Konsolenwarnung. Der Platzhalter nennt den _type, gibt den gespeicherten Blockwert aber nicht aus.
In der Produktion rendert ein nicht zugeordneter Typ die fallback-Komponente, sofern angegeben. Andernfalls erzeugt er keine Ausgabe:
---
import MissingBlock from "../../components/blocks/MissingBlock.astro";
---
<Blocks value={page.data.layout} components={components} fallback={MissingBlock} />
Liefern Sie die Renderer-Unterstützung aus, bevor Sie einen Blocktyp aktivieren, der von Produktionsinhalten verwendet wird.
Ein Block-Schema ändern
Kompatible Änderungen ergänzen die aktive Version. Das Hinzufügen eines optionalen Felds, das Hinzufügen eines Standardwerts oder das Lockern der Validierung behält dieselbe Versionsnummer bei. Gespeicherte Blöcke erhalten die Standardwerte beim nächsten Schreiben.
Eine inkompatible Änderung erzeugt eine inaktive Version. Das Entfernen eines Felds, das Ändern eines Feldtyps, das Hinzufügen eines Pflichtfelds oder das Verschärfen der Validierung ist inkompatibel.
-
Erstellen Sie die inkompatible Version über die Schema-API oder MCP. Lassen Sie sie inaktiv.
-
Aktualisieren Sie den Renderer so, dass er sowohl die beibehaltene als auch die neue Version verarbeitet. Stellen Sie den Renderer bereit.
-
Aktivieren Sie die neue Version. Neue Blöcke verwenden sie nach der Aktivierung.
-
Migrieren Sie gespeicherte Blöcke explizit mit
migrateBlocks: true. Behalten Sie dabei jeden Block-_keybei, während Sie_versionund die versionsspezifischen Felder ändern.
Alte Versionen bleiben für Revisionen, Entwürfe, Medien-Tracking und gespeicherte Inhalte verfügbar. Für Blocktypen und beibehaltene Versionen gibt es keine endgültige Löschoperation.
Unterstützte verschachtelte Felder
Block-Definitionen unterstützen string, text, url, number, integer, boolean, datetime, select, multiSelect, portableText, image, file und repeater.
Referenzen, JSON, Slugs, verschachtelte Blöcke, benutzerdefinierte Widgets, physische Indizes, Eindeutigkeit und Lokalisierung pro Unterfeld werden innerhalb einer Block-Definition nicht unterstützt. Ein blocks-Feld selbst kann nicht erforderlich, eindeutig, durchsuchbar, indiziert sein und erhält auch kein benutzerdefiniertes Feld-Widget.
Die genauen Regeln für die Feldvalidierung und gespeicherte Werte finden Sie in der Referenz zum blocks-Feld. Zu Seed-Konflikten und Exportverhalten siehe Seed-Dateien.