Deutsch
Renderer
@templatical/renderer konvertiert Templatical-Template-JSON in MJML. Funktioniert sowohl in Browser- als auch in Node.js-Umgebungen.
Der Renderer erzeugt ausschließlich MJML. Um MJML für den E-Mail-Versand zu HTML zu kompilieren, verwenden Sie eine beliebige MJML-Bibliothek (mjml für Node.js, spatie/mjml-php für PHP usw.).
bash
npm install @templatical/rendererbash
pnpm add @templatical/rendererbash
yarn add @templatical/rendererbash
bun add @templatical/rendererrenderToMjml(content, options?)
Rendert ein TemplateContent-Objekt zu einem MJML-String. Gibt ein Promise<string> zurück – asynchron, damit benutzerdefinierte Blöcke (deren Auflösung asynchrone Arbeit erfordern kann) inline gerendert werden können.
ts
import { renderToMjml } from '@templatical/renderer';
const mjml = await renderToMjml(templateContent);Parameter:
| Parameter | Type | Beschreibung |
|---|---|---|
content | TemplateContent | Das zu rendernde Template |
options | RenderOptions | Optionale Rendering-Konfiguration |
Rückgabewert: Promise<string> -- MJML-Markup
RenderOptions
ts
interface RenderOptions {
customFonts?: CustomFont[];
defaultFallbackFont?: string;
allowHtmlBlocks?: boolean; // Standard: true
renderCustomBlock?: (block: CustomBlock) => Promise<string>;
blockRenderers?: BlockRendererMap;
getCustomBlockStylesheet?: (customType: string) => string | undefined | null;
socialIconsBaseUrl?: string;
}| Option | Default | Beschreibung |
|---|---|---|
customFonts | [] | Definitionen benutzerdefinierter Schriftarten für <mj-font>-Deklarationen in der gerenderten Ausgabe |
defaultFallbackFont | 'Arial, sans-serif' | Fallback-Stack, der an eine benutzerdefinierte Schriftart ohne eigenen fallback oder an eine einzelne, nicht eingebaute Schriftfamilie angehängt wird. Ein vollständiger Stack wird unverändert ausgegeben. |
allowHtmlBlocks | true | Auf false setzen, um HTML-Blöcke aus der Ausgabe zu entfernen |
renderCustomBlock | -- | Wandelt benutzerdefinierte Blöcke in HTML um. Wird einmal pro benutzerdefiniertem Block aufgerufen. Editor-Konsumenten übergeben editor.renderCustomBlock; Headless-Konsumenten verwenden einen eigenen Resolver. Wenn weggelassen, fällt der Renderer auf das renderedHtml-Feld des Blocks zurück (falls vorhanden) und lässt den Block andernfalls weg. |
blockRenderers | {} | Typbezogene Renderer-Overrides, keyed nach block.type. Ein Countdown-GIF-Backend nutzt dies. Ein Override übernimmt die Prüfung auf „auf allen Viewports ausgeblendet“. |
getCustomBlockStylesheet | -- | (customType) => string | undefined | null. Wird einmal pro eindeutigem customType aufgerufen. Editor-Konsumenten übergeben das Registry-Stylesheet. Wenn weggelassen, wird stattdessen das renderedStylesheet jedes Typs ausgegeben (die Kopie, die der Editor schreibt, bevor ein Render-Provider oder der Cloud-Speicher den Inhalt sieht); wird es übergeben, entscheidet es für jeden Typ, und die Kopien werden ignoriert. |
socialIconsBaseUrl | versionsgebundene jsDelivr-URL | Basis-URL (ohne abschließenden Schrägstrich) für die PNG-Assets der Social-Media-Icons. Wird pro Icon zu ${baseUrl}/${dir}/${platform}.png aufgelöst, wobei dir der Stil ist, bei einem iconTone von dark oder light gefolgt von -${tone}. Siehe Social-Media-Icons unten. |
Benutzerdefinierte Blöcke
Wenn der Inhaltsbaum benutzerdefinierte Blöcke enthält, fragt der Renderer den übergebenen renderCustomBlock-Callback, um jeden in HTML zu konvertieren. Aus dem Editor:
ts
const mjml = await renderToMjml(editor.getContent(), {
renderCustomBlock: editor.renderCustomBlock,
});Headless- / Node.js-Konsumenten (ohne montierten Editor) können einen eigenen Resolver bereitstellen – zum Beispiel die gleiche Liquid-Vorlage gegen die fieldValues des Blocks ausführen:
ts
import { Liquid } from 'liquidjs';
const engine = new Liquid();
const definitionsByType = new Map(/* Ihre CustomBlockDefinition-Liste, nach type indiziert */);
const mjml = await renderToMjml(content, {
async renderCustomBlock(block) {
const definition = definitionsByType.get(block.customType);
if (!definition) return '';
return engine.parseAndRender(definition.template, block.fieldValues);
},
});Social-Media-Icons
Social-Icon-Blöcke werden als <img src="…/{dir}/{platform}.png"> ausgegeben. dir ist bei Markenfarben der Icon-Stil (circle) und bei einem iconTone von dark oder light {style}-{tone} (circle-dark). Der Standardwert von socialIconsBaseUrl verweist auf den versionsgebundenen jsDelivr-Mirror von @templatical/renderer, der vorgerasterte PNGs (jede SocialPlatform × 6 Stile × 3 Farbtöne) mit dem Paket ausliefert:
https://cdn.jsdelivr.net/npm/@templatical/renderer@<version>/assets/social/{dir}/{platform}.pngWarum PNGs. Outlook Desktop (Word-Rendering-Engine) unterstützt kein SVG und lehnt base64-Daten-URIs in <img src> ab. Gehostete PNGs sind das einzige Format, das in allen gängigen E-Mail-Clients zuverlässig dargestellt wird.
Warum versionsgebunden. E-Mails sind Archivinhalt — Empfänger öffnen Nachrichten Monate oder Jahre nach dem Versand. Die Versionsbindung friert die Icon-Darstellung zum Renderzeitpunkt ein, sodass ein späteres Redesign oder ein Regressionsfehler im Paket bereits zugestellte E-Mails nicht rückwirkend beschädigt. Außerdem entfällt eine 302-Weiterleitung pro Icon und es können langlebige, unveränderliche Cache-Header gesetzt werden.
Selbst hosten. Überschreiben Sie socialIconsBaseUrl, um die Assets über Ihr eigenes CDN auszuliefern — nützlich für Air-Gapped-Umgebungen, markenspezifische Themen oder um die Abhängigkeit von jsDelivr zu entfernen:
ts
const mjml = await renderToMjml(content, {
socialIconsBaseUrl: 'https://cdn.example.com/email-assets/social',
});Die exakten Dateinamen, die der Renderer erwartet, sind {dir}/{platform}.png, wobei dir ein style aus solid | outlined | rounded | square | circle | plain ist, für diese Farben gefolgt von -dark oder -light (ein Icon in Markenfarbe hat kein Suffix), und platform einer von facebook | twitter | instagram | linkedin | youtube | tiktok | pinterest | email | whatsapp | telegram | discord | snapchat | reddit | github | dribbble | behance | website ist. Die ausgelieferten 144×144-PNGs sind ein sinnvoller Ausgangspunkt, wenn Sie sie spiegeln möchten.
Das Paket exportiert außerdem DEFAULT_SOCIAL_ICONS_BASE_URL, falls Sie URLs gegen denselben Standardwert komponieren möchten:
ts
import { DEFAULT_SOCIAL_ICONS_BASE_URL } from '@templatical/renderer';Hilfsfunktionen
Der Renderer exportiert außerdem Hilfsfunktionen:
ts
import {
escapeHtml,
escapeAttr,
convertMergeTagsToValues,
isHiddenOnAll,
toPaddingString,
renderBlock,
getCssClassAttr,
getCssClasses,
getWidthPercentages,
getWidthPixels,
fluidOnMobileAttr,
DEFAULT_SOCIAL_ICONS_BASE_URL,
RenderContext,
} from '@templatical/renderer';escapeHtml(text)
Maskiert HTML-Entitäten (<, >, &, ", ') in einem String. Verwenden Sie dies, wenn Sie Benutzerinhalte in HTML einfügen:
ts
escapeHtml('<script>alert("xss")</script>');
// '<script>alert("xss")</script>'escapeAttr(text)
Maskiert einen String für die sichere Verwendung in HTML-Attributwerten:
ts
const alt = escapeAttr('Photo of "sunrise" at O\'Hare');
// 'Photo of "sunrise" at O'Hare'convertMergeTagsToValues(html)
Konvertiert HTML-Spans für Merge-Tags (vom Rich-Text-System des Editors intern verwendet) zurück in ihre einfache Textsyntax. Der Editor speichert Merge-Tags als <span data-merge-tag="...">-Elemente; diese Funktion entfernt die Spans und lässt die rohe Merge-Tag-Syntax übrig:
ts
import { convertMergeTagsToValues } from '@templatical/renderer';
// Eingabe: internes HTML-Format des Editors
const editorHtml = '<span data-merge-tag="{{ first_name }}">First Name</span>';
const cleaned = convertMergeTagsToValues(editorHtml);
// Ausgabe: '{{ first_name }}'TIP
Sie müssen diese Funktion normalerweise nicht direkt aufrufen — der Renderer ruft sie intern beim Verarbeiten von Title- und Paragraph-Blöcken auf. Sie wird für fortgeschrittene Anwendungsfälle exportiert, in denen Sie mit Editor-HTML außerhalb der normalen Rendering-Pipeline arbeiten.
isHiddenOnAll(block)
Gibt true zurück, wenn bei der visibility eines Blocks alle Viewports auf false gesetzt sind. Nützlich, um Blöcke zu überspringen, die überhaupt nicht gerendert werden sollen:
ts
if (isHiddenOnAll(block)) {
// Diesen Block vollständig überspringen
}toPaddingString(padding)
Konvertiert einen SpacingValue in einen CSS-Padding-String:
ts
toPaddingString({ top: 10, right: 20, bottom: 10, left: 20 });
// '10px 20px 10px 20px'renderBlock(block, context)
Rendert einen einzelnen Block in seine MJML-Darstellung. Wird intern von renderToMjml() verwendet, aber für fortgeschrittene Anwendungsfälle exportiert, in denen Sie einzelne Blöcke rendern müssen.
RenderContext
Das an Block-Renderer übergebene Kontextobjekt. Enthält Rendering-Optionen, Schriftart-Konfiguration und zwei Breiten:
| Feld | Wert |
|---|---|
containerWidth | Der Anteil der Spalte an der Body-Breite, ohne Padding und Rahmen um sie herum. Ein Bild oder Video mit 'full' wird in dieser Breite ausgegeben, und MJML begrenzt es auf seine tatsächliche Box. |
contentWidth | Die ganzen Pixel, die MJML dem Inhalt der Spalte gibt: die Body-Breite abzüglich des seitlichen Paddings und Rahmens von Wrapper-Band und Sektion, davon der Prozentanteil der Spalte, abgerundet. Breitenabhängige Entscheidungen lesen diesen Wert. |
withContainerWidth(width, contentWidth = width) gibt eine Kopie für einen schmaleren Container zurück.
fluidOnMobileAttr(block, context)
Gibt ' fluid-on-mobile="true"' für ein Bild zurück, das seine Spalte auf dem Desktop füllt, sonst ''. Ein Bild füllt seine Spalte, wenn seine width 'full' ist oder eine Pixelbreite, die context.contentWidth abzüglich des seitlichen Paddings und Rahmens des Blocks erreicht oder überschreitet. Siehe Breite auf Smartphones.
Die eingebauten Bild- und Video-Renderer verwenden sie. Eine blockRenderers-Überschreibung, die ein eigenes mj-image ausgibt, ruft sie ebenfalls auf; ohne das Attribut behält das Bild auf dem Smartphone seine Desktop-Breite:
ts
blockRenderers: {
image: (block, ctx) => {
const image = block as ImageBlock;
const width = image.width === 'full' ? ctx.containerWidth : image.width;
return `<mj-image src="${escapeAttr(image.src)}" width="${width}px"${fluidOnMobileAttr(image, ctx)} />`;
},
},getCssClassAttr(block) / getCssClasses(block)
Erzeugen CSS-Klassen-Attribute aus den Sichtbarkeitseinstellungen eines Blocks. Wird intern für responsives Ausblenden verwendet.
getWidthPercentages(layout) / getWidthPixels(layout, containerWidth)
Berechnen Spaltenbreiten für ein gegebenes ColumnLayout. Gibt ein Array von Prozent- oder Pixelwerten pro Spalte zurück.
DEFAULT_SOCIAL_ICONS_BASE_URL
Der Standardwert von RenderOptions.socialIconsBaseUrl — die versionsgebundene jsDelivr-URL, die auf die in diesem Paket mitgelieferten PNGs der Social-Media-Icons verweist. Siehe Social-Media-Icons.
MJML zu HTML kompilieren
Nach dem Rendern in MJML kompilieren Sie mit einer beliebigen MJML-Bibliothek zu HTML:
ts
import { renderToMjml } from '@templatical/renderer';
import mjml2html from 'mjml';
const mjml = await renderToMjml(templateContent);
const { html } = mjml2html(mjml);
// html ist bereit zum Versand über Ihren E-Mail-DienstWeitere Informationen zur Rendering-Pipeline finden Sie unter Wie das Rendering funktioniert.