Ein blocks-Feld speichert eine geordnete Seitenkomposition. Jedes Element erfasst einen Blocktyp, eine beibehaltene Schema-Version, einen stabilen Schlüssel und die Felder, die von dieser Version deklariert werden. Redakteure fügen Blöcke im Content-Editor 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 Hero- und Feature-Grid-Blöcke und stellt sie dann in einem layout-Feld der Collection Pages bereit:
{
"$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. Wenn Sie später einen erlaubten Typ entfernen, verschiebt EmDash ihn in die vom Server verwaltete Liste retiredTypes. Vorhandene Blöcke bleiben bearbeitbar, aber Redakteure können diesen Typ weder hinzufügen noch 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 vorauszusetzen. Ü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.redirect("/404");
const { entry: page, cacheHint } = await getEmDashEntry("pages", slug);
if (!page) return Astro.redirect("/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 andere 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 aber den gespeicherten Blockwert nicht aus.
In der Produktion rendert ein nicht zugeordneter Typ die fallback-Komponente, sofern eine angegeben ist. Andernfalls wird nichts ausgegeben:
---
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 Feldes, das Hinzufügen eines Standardwerts oder das Lockern der Validierung behält dieselbe Versionsnummer bei. Gespeicherte Blöcke erhalten Standardwerte, wenn sie das nächste Mal geschrieben werden.
Eine inkompatible Änderung erstellt eine inaktive Version. Das Entfernen eines Feldes, das Ändern eines Feldtyps, das Hinzufügen eines Pflichtfeldes 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, sodass 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. Bewahren Sie den_keyjedes Blocks, 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 keinen Vorgang zum endgültigen Löschen.
Unterstützte verschachtelte Felder
Blockdefinitionen 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 Blockdefinition nicht unterstützt. Ein Blocks-Feld selbst kann nicht als Pflichtfeld, eindeutig, durchsuchbar oder indiziert markiert werden und kann kein benutzerdefiniertes Feld-Widget erhalten.
Die genauen Regeln zur Feldvalidierung und zu gespeicherten Werten finden Sie in der Referenz zum blocks-Feld. Informationen zu Seed-Konflikten und zum Exportverhalten finden Sie unter Seed-Dateien.