Anleitung: Eine Scryfall-Integration für Eleventy selbst bauen
Disclaimer: Dieser Blogpost wurde im Rahmen eines Test von einer KI geschrieben. Author ist Gemini Code Assist 2.5 Pro.
Schritt 1: Das Ziel und die Werkzeuge
Unser Ziel ist es, einen einfachen Shortcode zu erstellen, der ein ansprechendes Bild und Metadaten für die entsprechende Karte rendert.
Dafür benötigen wir einige Dinge:
- Ein Eleventy-Projekt.
- Die Scryfall API, um Kartendaten zu erhalten.
- Das
@11ty/eleventy-imgPlugin, um Bilder effizient zu verarbeiten.
Schritt 2: Die Shortcode-Datei erstellen
Zuerst erstellen wir eine dedizierte JavaScript-Datei für unsere Shortcode-Logik. Ich habe eine Datei namens scryfall.js im Stammverzeichnis meines Projekts erstellt. Diese wird die gesamte Logik für das Abrufen von Daten, das Caching und die Erzeugung des finalen HTML-Codes enthalten.
Schritt 3: Kartendaten von Scryfall abrufen
In scryfall.js benötigen wir eine Funktion, um Kartendaten von der Scryfall-API zu beziehen. Wir verwenden eine fetch-Anfrage an deren API-Endpunkt. Entscheidend ist, dass wir die Ergebnisse zwischenspeichern (cachen). Die API bei jedem einzelnen Build aufzurufen wäre sehr langsam und könnte dazu führen, dass wir von der API blockiert werden (Rate-Limiting).
Hier ist eine vereinfachte Version der Datenabruffunktion:
// In scryfall.js
const fs = require("node:fs/promises");
const path = require("node:path");
const SCRYFALL_CACHE_DIR = path.join(".cache", "scryfall");
async function getScryfallCard(query) {
const cacheKey = query.toLowerCase().replace(/[^a-z0-9]/g, "");
const cachePath = path.join(SCRYFALL_CACHE_DIR, `${cacheKey}.json`);
// Zuerst versuchen, aus dem Cache zu lesen
try {
const cachedData = JSON.parse(await fs.readFile(cachePath, "utf8"));
// Hier könntest du eine Gültigkeitsprüfung (Time-To-Live, TTL) einbauen
return cachedData;
} catch (error) {
// Wenn nicht im Cache, von der API abrufen
}
await fs.mkdir(SCRYFALL_CACHE_DIR, { recursive: true });
const url = `https://api.scryfall.com/cards/named?fuzzy=${encodeURIComponent(query)}`;
const response = await fetch(url);
const data = await response.json();
// Für das nächste Mal im Cache speichern
await fs.writeFile(cachePath, JSON.stringify(data, null, 2), "utf8");
return data;
}
Code-Erklärung im Detail:
const fs = require("node:fs/promises");undconst path = require("node:path");: Wir importieren zwei Kernmodule von Node.js.fs/promiseserlaubt uns, mit dem Dateisystem zu arbeiten (z.B. Dateien zu lesen und zu schreiben) und dabei moderneasync/await-Syntax zu verwenden.pathstellt Hilfsfunktionen zur Verfügung, um Dateipfade auf eine Weise zu erstellen, die auf allen Betriebssystemen (Windows, macOS, Linux) funktioniert.const cacheKey = ...: Wir erstellen einen eindeutigen und für Dateisysteme sicheren Namen für unsere Cache-Datei. Wir nehmen den Suchbegriff (query), wandeln ihn in Kleinbuchstaben um und entfernen alle Zeichen, die keine Buchstaben oder Zahlen sind. Das verhindert Fehler durch ungültige Zeichen in Dateinamen.const cachePath = path.join(...): Wir setzen den vollständigen Pfad zu unserer Cache-Datei zusammen, z.B..cache/scryfall/blacklotus.json.try { ... } catch (error) { ... }: Dies ist ein fundamentaler Mechanismus für die Fehlerbehandlung. Wir versuchen (try), die Cache-Datei zu lesen und deren Inhalt als JSON zu parsen. Wenn das fehlschlägt (z.B. weil die Datei noch nicht existiert), fangen wir den Fehler imcatch-Block ab und machen einfach weiter. Das ist der erwartete Fall, wenn eine Karte zum ersten Mal abgefragt wird.await fs.mkdir(..., { recursive: true });: Dieser Befehl stellt sicher, dass unser Cache-Verzeichnis (.cache/scryfall) existiert. Die Option{ recursive: true }sorgt dafür, dass kein Fehler ausgeworfen wird, falls das Verzeichnis bereits vorhanden ist.const url = ...: Wir bauen die URL für die Scryfall-API zusammen.encodeURIComponent(query)ist hier sehr wichtig. Es wandelt den Kartennamen so um, dass er sicher in einer URL verwendet werden kann (z.B. werden Leerzeichen durch%20ersetzt).await fs.writeFile(...): Nachdem wir die Daten erfolgreich von der API geholt haben, schreiben wir sie in unsere Cache-Datei.JSON.stringify(data, null, 2)formatiert das JSON leserlich mit Einrückungen, was die Fehlersuche erleichtert.
Schritt 4: Bildverarbeitung mit eleventy-img
Die Kartendaten von Scryfall enthalten eine URL zum Bild der Karte. Wir könnten einfach diese URL in einem <img>-Tag verwenden, aber das ist ineffizient. Stattdessen verwenden wir @11ty/eleventy-img, um das Bild herunterzuladen, seine Größe anzupassen und es in moderne Formate wie WebP und AVIF zu konvertieren.
Dies geschieht innerhalb unserer Haupt-Shortcode-Funktion.
Schritt 5: Die asynchrone Shortcode-Funktion
Nun führen wir alles in einer async-Shortcode-Funktion in scryfall.js zusammen.
// In scryfall.js
const Image = require("@11ty/eleventy-img");
async function scryfallShortcode(query) {
// 1. Kartendaten abrufen (aus dem Cache oder von der API)
const card = await getScryfallCard(query);
// 2. Bild-URL aus den Daten extrahieren
const imageUrl = card.image_uris?.normal;
if (!imageUrl) {
return `<p>Kein Bild für ${query} gefunden</p>`;
}
// 3. Bild mit eleventy-img verarbeiten
const metadata = await Image(imageUrl, {
widths: [672], // maximale Breite des Bildes
formats: ["avif", "webp", "jpeg"],
outputDir: path.join("_site", "img", "scryfall"),
urlPath: "/img/scryfall",
});
// 4. HTML für das responsive Bild generieren
const pictureMarkup = Image.generateHTML(metadata, {
alt: card.name,
loading: "lazy",
decoding: "async",
});
// 5. Finales HTML für die Kartenanzeige zurückgeben
return `<figure class="scryfall-card">
<a href="${card.scryfall_uri}" target="_blank" rel="noopener noreferrer">
${pictureMarkup}
</a>
<figcaption>${card.name}</figcaption>
</figure>`;
}
// Nicht vergessen, die Funktion zu exportieren
module.exports.scryfallShortcode = scryfallShortcode;
Code-Erklärung im Detail:
const card = await getScryfallCard(query);: Wir rufen unsere zuvor definierte Funktion auf, um die Kartendaten zu erhalten.const imageUrl = card.image_uris?.normal;: Wir holen die URL zum Bild. Das?.(Optional Chaining) ist eine Sicherheitsmaßnahme: Falls dasimage_uris-Objekt nicht existiert, wird der Ausdruck zuundefinedund verursacht keinen Fehler.const metadata = await Image(...): Das ist der Kern voneleventy-img. Wir übergeben die Bild-URL und ein Konfigurationsobjekt:widths: [672]: Wir geben an, in welchen Breiten das Bild erzeugt werden soll. Für responsive Designs kann man hier mehrere Breiten angeben (z.B.[300, 600, 900]).formats: ["avif", "webp", "jpeg"]:eleventy-imgerzeugt das Bild in all diesen Formaten. Moderne Browser können das hocheffiziente AVIF-Format laden, ältere greifen auf WebP oder das universelle JPEG zurück.outputDir: Dies ist der physische Ordner, in dem die verarbeiteten Bilder gespeichert werden (innerhalb deines finalen Build-Ordners_site).urlPath: Dies ist der öffentliche Pfad, der im HTML-Code imsrc-Attribut des Bildes verwendet wird (z.B./img/scryfall/bild.webp).
const pictureMarkup = Image.generateHTML(...): Diese extrem nützliche Hilfsfunktion voneleventy-imgnimmt diemetadatavom vorherigen Schritt und erzeugt das komplette HTML für ein responsives Bild. Das Ergebnis ist ein<picture>-Element, das verschiedene<source>-Tags für die unterschiedlichen Formate und Breiten sowie ein Fallback-<img>-Tag enthält. Wir müssen diesen komplexen HTML-Code also nicht von Hand schreiben.return <figure>...: Wir wickeln unser Bild in ein<figure>-Element ein, was semantisch korrekt ist für Inhalte wie Bilder, die eine Beschriftung haben. Der Link führt zur offiziellen Scryfall-Seite der Karte, und die<figcaption>dient als Bildunterschrift.
Schritt 6: Den Shortcode in Eleventy registrieren
Der letzte Schritt ist, Eleventy über unseren neuen Shortcode zu informieren. Das tun wir in der Konfigurationsdatei eleventy.config.js.
// In eleventy.config.js
const { scryfallShortcode } = require("./scryfall.js");
module.exports = function (eleventyConfig) {
// ... andere Konfigurationen
eleventyConfig.addNunjucksAsyncShortcode("scryfall", scryfallShortcode);
};
Code-Erklärung im Detail:
Da unser Shortcode await für API-Anfragen und Bildverarbeitung verwenden muss, müssen wir ihn als asynchronen Shortcode registrieren. addNunjucksAsyncShortcode macht genau das. Der Name "scryfall" ist der Name, den wir in unseren Markdown- oder Nunjucks-Dateien verwenden werden.
Schritt 7: Den Shortcode verwenden
Das war's! Jetzt kannst du den Shortcode in jeder deiner Markdown- oder Nunjucks-Dateien verwenden.
Probieren wir es mit einer klassischen Karte aus:
Dieser Aufruf wird nun automatisch die Daten für Black Lotus abrufen, das Bild verarbeiten und das von uns definierte HTML rendern. Beim nächsten Build wird es blitzschnell gehen, da die Daten und Bilder direkt aus dem Cache gelesen werden.
Ich hoffe, diese Anleitung hilft dir dabei, deine eigenen coolen Integrationen mit Eleventy zu bauen!

