Dieser Leitfaden stellt eine EmDash-Site auf Cloudflare Workers mit D1 für die Datenbank und R2 für Medien bereit. Beginnen Sie mit einer EmDash Cloudflare-Vorlage oder wenden Sie dieselbe Konfiguration auf eine bestehende Astro-Site an.
Voraussetzungen
- Ein Cloudflare-Konto
- Die installierten Projektabhängigkeiten
- Bei Cloudflare authentifiziertes Wrangler (
pnpm wrangler login)
Bindings konfigurieren
Die Cloudflare-Vorlagen enthalten den vollständigen Worker-Entry-Point sowie benannte D1- und R2-Bindings. Beim ersten Deploy legt Wrangler beide Ressourcen an, falls der konfigurierte Name noch nicht existiert. Behalten Sie die Namen in wrangler.jsonc bei; Wrangler verbindet spätere Deployments wieder mit denselben Ressourcen.
Die Vorlage verwendet die folgenden Bindings:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-emdash-site",
"main": "./src/worker.ts",
"compatibility_date": "2026-02-24",
"compatibility_flags": ["nodejs_compat"],
"d1_databases": [
{
"binding": "DB",
"database_name": "my-emdash-site",
},
],
"r2_buckets": [
{
"binding": "MEDIA",
"bucket_name": "my-emdash-media",
},
],
"worker_loaders": [{ "binding": "LOADER" }],
"triggers": { "crons": ["* * * * *"] },
}
Die Namen DB, MEDIA und LOADER müssen zu den EmDash-Adaptern passen. Der Cron Trigger führt das geplante Veröffentlichen, Plugin-Aufgaben, Backups und Wartung aus. Siehe Plugin sandbox, wenn die Site Sandbox-Plugins verwendet.
EmDash konfigurieren
Die folgende Astro-Konfiguration verwendet die D1- und R2-Bindings.
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
import react from "@astrojs/react";
import emdash from "emdash/astro";
import { d1, r2, sandbox } from "@emdash-cms/cloudflare";
export default defineConfig({
output: "server",
adapter: cloudflare(),
integrations: [
react(), // Required — the admin UI is a React app
emdash({
database: d1({ binding: "DB" }),
storage: r2({ binding: "MEDIA" }),
sandboxRunner: sandbox(),
}),
],
});
Wenn die Site keine Marketplace-, Registry- oder sandboxed-Plugins verwendet, lassen Sie sandboxRunner und das LOADER-Binding weg.
Worker-Entry-Point hinzufügen
Der Worker-Entry-Point verbindet Astro mit dem Cron Trigger und exportiert die Plugin-Bridge:
import handler, { createScheduledHandler, PluginBridge } from "@emdash-cms/cloudflare/worker";
export { PluginBridge };
export default {
...handler,
scheduled: createScheduledHandler(),
} satisfies ExportedHandler;
Der Export von PluginBridge ist harmlos, wenn kein Sandbox-Plugin installiert ist. Behalten Sie ihn bei, wenn dasselbe Projekt später Plugins aktivieren könnte.
Um allgemeine Wartung nach einem anderen Zeitplan als jede Minute auszuführen, übergeben Sie denselben Cron-Ausdruck an createScheduledHandler({ generalCron: "..." }) und an triggers.crons. Wenn sie sich unterscheiden, protokolliert der Handler den unerwarteten Trigger und ignoriert ihn.
Build und Bereitstellung
Bauen Sie die Site einmal und stellen Sie sie bereit, damit Wrangler die benannte D1-Datenbank und den R2-Bucket anlegt. Wrangler verwendet die lokale Anmeldung, die pnpm wrangler login erstellt hat.
pnpm build
pnpm wrangler deploy
Im standardmäßigen Migrationsmodus auto wendet EmDash ausstehende Core-Migrationen an, sobald der bereitgestellte Worker seine erste Anfrage erhält. Verwenden Sie Manage core database migrations, wenn eine Deployment-Pipeline Migrationen anwenden muss, bevor neuer Code Traffic erhält, oder wenn Sie eine Migration prüfen, kontrollieren oder wiederherstellen müssen.
Bis der Einrichtungsassistent abgeschlossen ist, wendet EmDash bei der ersten Anfrage außerdem einmalig das Schema und die Struktur einer Seed-Datei an. Beispielinhalte aus dem Seed werden nur angewendet, wenn ein Administrator sie im Einrichtungsassistenten auswählt. Der Seed wird zur Build-Zeit aus .emdash/seed.json, dem Pfad in package.json#emdash.seed oder seed/seed.json gelesen – je nachdem, was zuerst gefunden wird – und in das Bundle eingebettet. Ist keiner vorhanden, wird ein integrierter Standard-Seed verwendet. Spätere Deployments gegen eine bestehende Datenbank lassen deren Inhalt unangetastet.
Informationen zum Ändern des Schemas oder Inhaltsmodells einer bereits bereitgestellten Site finden Sie unter Evolving a Deployed Site.
Geplantes Veröffentlichen
Auf Cloudflare veröffentlicht EmDash geplante Einträge nur über den scheduled-Handler des Workers, den Cloudflare nach dem Zeitplan eines Cron Trigger aufruft. Der bereitgestellte Worker benötigt beides:
- Einen Cron Trigger in der Liste
triggers.cronsvonwrangler.jsonc, wie unter Bindings konfigurieren gezeigt. - Den
scheduled-Handler aus@emdash-cms/cloudflare/worker, exportiert aus dem Worker-Entry-Point, auf denmainzeigt, wie unter Worker-Entry-Point hinzufügen gezeigt.
Fehlt eines von beiden, gehen geplante Einträge nicht live. In der lokalen Entwicklung mit astro dev veröffentlicht EmDash geplante Einträge über einen Timer, sodass ein lokal funktionierender Zeitplan die bereitgestellte Konfiguration nicht bestätigt.
Führen Sie emdash doctor im Projektstamm aus, um den Cron Trigger und den scheduled-Handler in den lokalen Projektdateien zu prüfen:
pnpm emdash doctor
Findet emdash doctor beides, enthält die Ausgabe eine bestandene Prüfung scheduler wiring. Eine fehlgeschlagene Scheduler-Prüfung beschreibt das Problem und gibt die Behebung aus. Die Prüfung erkennt den auf dieser Seite gezeigten Worker-Entry-Point und den einzeiligen Re-Export, den sie als Behebung ausgibt. Ein auf andere Weise geschriebener Entry-Point kann die Prüfung daher auch dann nicht bestehen, wenn er funktioniert.
Erscheint keine Scheduler-Prüfung, hat emdash doctor im aktuellen Verzeichnis keine Wrangler-Konfiguration gefunden oder weder den Cron Trigger noch den scheduled-Handler. Bei einem D1-Projekt schlägt die Prüfung database fehl, weil sie nach einer lokalen SQLite-Datei sucht (standardmäßig ./data.db). Dieser Fehler beeinflusst die Scheduler-Prüfungen nicht.
Stellen Sie erneut bereit, nachdem Sie den Cron Trigger oder den scheduled-Handler hinzugefügt oder geändert haben. Cloudflare kann bis zu 15 Minuten brauchen, um einen neuen oder geänderten Cron Trigger auszuführen. Sobald der Trigger läuft, veröffentlicht EmDash Einträge, deren geplante Zeit bereits verstrichen ist.
Um den Trigger zu beobachten, führen Sie pnpm wrangler tail aus. Jede Ausführung gibt eine Zeile wie "* * * * *" @ 9/29/2026, 10:01:00 AM - Ok aus. Ok bedeutet, dass die Ausführung ohne nicht abgefangenen Fehler endete. EmDash fängt Fehler beim Veröffentlichen ab und protokolliert sie, daher bestätigt Ok nicht, dass Einträge veröffentlicht wurden. Eine Ausführung, die Einträge veröffentlicht, protokolliert außerdem eine Meldung wie [scheduled] Published 1 scheduled item(s), und Fehler der Ausführung erscheinen in derselben Ausgabe.
Nach der Bereitstellung zeigt das Admin-Dashboard Scheduled publishing needs attention an, wenn ein geplanter Eintrag seine geplante Zeit überschritten hat und in den letzten fünf Minuten kein Scheduler-Lauf abgeschlossen wurde. Läuft der Cron Trigger seltener als alle fünf Minuten, kann der Hinweis auch zwischen den Läufen erscheinen, bis der nächste Lauf den Eintrag veröffentlicht.
Worker nahe bei D1 platzieren
Cloudflare führt einen Worker standardmäßig in der Nähe des Besuchers aus. Serverseitig gerenderte EmDash-Anfragen machen mehrere Round Trips zu D1. Verwenden Sie daher Targeted Placement, um den Worker nahe beim D1-Primary auszuführen und diese Anfragen zu beschleunigen.
Wrangler akzeptiert placement.mode: "targeted" mit genau einem Selektor: region, host oder hostname. Wählen Sie den Wert, der auf den Standort des D1-Primary zielt, und fügen Sie das resultierende placement-Objekt zu wrangler.jsonc hinzu. Aktivieren Sie keine D1-Read-Replicas zusammen mit Targeted Placement. Belassen Sie die EmDash-Einstellung session auf ihrem Standardwert "disabled", damit Lese- und Schreibzugriffe den nahen Primary verwenden.
Object Cache
Um die Leselast auf D1 zu verringern, können Sie Abfrageergebnisse für Inhalte und Konfiguration in Cloudflare KV zwischenspeichern. Lesezugriffe werden aus KV bedient, statt bei jeder Anfrage die Datenbank abzufragen:
import { d1, r2, kvCache } from "@emdash-cms/cloudflare";
emdash({
database: d1({ binding: "DB" }),
storage: r2({ binding: "MEDIA" }),
objectCache: kvCache({ binding: "CACHE" }),
}),
Siehe Object Cache für KV-Einrichtung, Optionen und Invalidierungsverhalten.
Workers Cache
Der Workers Cache von Cloudflare setzt einen Edge-Cache vor Ihren Worker: Passende Anfragen werden bedient, ohne dass Ihr Worker überhaupt läuft.
Aktivieren
-
Verwenden Sie den Cloudflare-Cache-Provider von Astro, damit Routenregeln und
Astro.cacheCache-Header setzen und die Invalidierungcache.purge()verwendet.import { cacheCloudflare } from "@astrojs/cloudflare/cache"; export default defineConfig({ adapter: cloudflare(), cache: { provider: cacheCloudflare(), }, routeRules: { "/": { maxAge: 300, swr: 86400 }, // Other public routes can use different cache lifetimes. }, });Der Adapter
@astrojs/cloudflareerkenntcacheCloudflare()und aktiviert Workers Cache in der generierten Deployment-Konfiguration. -
Leeren Sie zwischengespeicherte Antworten aus Worker-Code mit der Plattform-API. Dieser Aufruf benötigt keine Cloudflare-REST-Zugangsdaten.
import { cache } from "cloudflare:workers"; await cache.purge({ purgeEverything: true }); // Or purge selected tags: await cache.purge({ tags: ["posts"] });
Antworten der EmDash-Administration und API senden bereits Cache-Control: private, no-store und werden nie gespeichert. Öffentliche Seiten steuern ihr eigenes Caching über Cache-Control / routeRules / Astro.cache.
Zwei Dinge sollten Sie vor der Aktivierung wissen:
- Antworten ohne
Cache-Control-Header werden dennoch zwischengespeichert. Workers Cache wendet die heuristische Frische nach RFC 9111 an – eine200ohne jeden Header wird 2 Stunden lang zwischengespeichert. Geben Sie jeder benutzerdefinierten Route ein explizitesCache-Control(verwenden Sieprivate, no-storefür alles, was von der Sitzung abhängt). - Zwischengespeicherte Seiten werden mit angemeldeten Redakteuren geteilt. Der Cache läuft vor Ihrem Worker und kann daher nicht anhand von Request-Cookies umgangen werden. Ein angemeldeter Redakteur erhält möglicherweise die zwischengespeicherte anonyme Variante einer öffentlichen Seite – ohne die visuelle Bearbeitungsleiste –, bis der Eintrag abläuft. Für Redakteure gerenderte Antworten werden selbst nie gespeichert (sie tragen
private, no-store), sodass in die andere Richtung nichts durchsickert.
Workers Caching ist vom Object Cache (objectCache: kvCache({ binding: "CACHE" })) getrennt, der Datenbankabfrageergebnisse in KV unterhalb des Workers zwischenspeichert.
Custom Domains
Das erste Deployment erhält eine workers.dev-URL. Die Custom Domain muss bereits eine aktive, von Cloudflare verwaltete Domain im selben Konto wie der Worker sein. Sobald der Worker unter seiner workers.dev-URL erfolgreich antwortet, fügen Sie die Produktionsdomain als Wrangler-Route hinzu:
{
"routes": [{ "pattern": "www.example.com", "custom_domain": true }],
}
Stellen Sie erneut bereit und prüfen Sie beide Adressen. Die workers.dev-Adresse während des DNS-Tests verfügbar zu halten, hilft dabei, ein Routingproblem von einem Anwendungsproblem zu unterscheiden. Damit die neue Domain zur Adresse in Sitemaps und Suchmetadaten wird, und in E-Mails und Plugins, wenn siteUrl, EMDASH_SITE_URL oder SITE_URL nicht gesetzt ist, verwenden Sie Change domain unter Settings > General; siehe Zu einer neuen Domain wechseln.
Ohne siteUrl, EMDASH_SITE_URL oder SITE_URL speichert die Einrichtung die Adresse, unter der sie läuft, als Origin der Website, und während der Einrichtung erstellte Passkeys funktionieren nur unter dieser Adresse. Führen Sie die Einrichtung auf der Produktionsdomain aus oder setzen Sie EMDASH_SITE_URL vor der Einrichtung auf diese Domain. Wenn Sie EMDASH_SITE_URL nach der Einrichtung auf eine andere Domain setzen, wandert die Anmeldung zu dieser Domain, und auf der alten Adresse erstellte Passkeys funktionieren dort nicht mehr.
Öffentlicher R2-Zugriff
Standardmäßig werden Medien über die authentifizierte Medienroute von EmDash ausgeliefert. Hat der Bucket eine öffentliche Custom Domain, setzen Sie diesen Origin als publicUrl, damit generierte Medien-URLs ihn verwenden:
storage: r2({
binding: "MEDIA",
publicUrl: "https://media.example.com",
}),
Öffentlicher Bucket-Zugriff gilt für jedes erreichbare Objekt, nicht nur für Medien. Automatische JSON-Backups verwenden das Präfix backups/ im selben Storage-Backend, geben Sie dieses Präfix also nicht über die öffentliche Domain frei. Choose media storage erklärt die sichere Grenze.
Bildtransformation
EmDash skaliert und kodiert R2-Medien innerhalb des Workers über das IMAGES-Binding von Cloudflare neu. Die Image-Komponente aus emdash/ui und Bilder in Rich Text werden beide über den Bild-Endpunkt gerendert, den EmDash unter dem Cloudflare-Adapter installiert. Bei Medien auf der internen Route /_emdash/api/media/file/… liest dieser Endpunkt die Quellbytes direkt aus dem R2-Binding, ohne HTTP-Fetch. Diese Transformationen funktionieren weiterhin hinter Cloudflare Access und mit global_fetch_strictly_public. Medien, die über eine Bucket-URL ausgeliefert werden – siehe Öffentlicher R2-Zugriff –, nutzen stattdessen den eigenen Transformations-Endpunkt des Adapters, der die Datei vor der Transformation per HTTP abruft.
Sie müssen das Binding nicht deklarieren. @astrojs/cloudflare fügt es während astro build zur generierten Worker-Konfiguration hinzu, so wie es cache für Workers Caching hinzufügt. Das geschieht immer dann, wenn der Laufzeit-Bilddienst cloudflare-binding ist: imageService nicht gesetzt, der String selbst oder { runtime: "cloudflare-binding" }. Jeder andere Wert – "passthrough", "compile", "cloudflare", "custom" – lässt das Binding weg. Es in Ihrer eigenen wrangler.jsonc aufzuführen, macht die Absicht eindeutig:
{
"images": {
"binding": "IMAGES",
},
}
Um zu sehen, was ein Deployment tatsächlich erhält, lesen Sie die generierte Konfiguration statt wrangler.jsonc. Ein Build schreibt .wrangler/deploy/config.json, die wrangler deploy auf die zusammengeführte Datei verweist (standardmäßig dist/server/wrangler.json). Suchen Sie dort nach einem images-Eintrag.
Cloudflare berechnet diese Transformationen als Images transformations. Jede eindeutige Kombination aus Quellbild und Parametern wird einmal pro Kalendermonat berechnet, wiederholte Anfragen innerhalb dieses Monats sind kostenlos. Hat eine Site 500 Quellbilder und fordert für jedes Bild eine Thumbnail-Größe und eine Hero-Größe an, zählen diese beiden Parametersätze für diesen Monat als 1.000 transformierte Bilder. Der Images-Free-Plan deckt 5.000 eindeutige Transformationen pro Monat ab. Darüber hinaus werden zwischengespeicherte Transformationen weiterhin ausgeliefert, neue geben jedoch einen 9422-Fehler zurück und die Bildanfrage schlägt fehl.
Cloudflare Access-Authentifizierung
Cloudflare Access kann die Passkey-Authentifizierung durch den Identitätsanbieter ersetzen, der an eine Access-Anwendung angebunden ist. Der Audience-Wert ist eine geheime Laufzeiteinstellung; halten Sie ihn aus astro.config.mjs heraus, indem Sie stattdessen den Namen seiner Umgebungsvariable angeben:
import { access } from "@emdash-cms/cloudflare";
emdash({
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audienceEnvVar: "CF_ACCESS_AUDIENCE",
roleMapping: {
Admins: 50,
Editors: 40,
},
}),
}),
Setzen Sie CF_ACCESS_AUDIENCE mit pnpm wrangler secret put CF_ACCESS_AUDIENCE. Der authentication guide erklärt Benutzerbereitstellung, Standardrollen und Rollensynchronisierung.
Produktions-Worker haben keinen standardmäßigen E-Mail-Zustelldienst. Die Anmeldung per Magic Link gibt Email is not configured zurück, bis ein E-Mail-Plugin aktiv ist.
Das Cloudflare-E-Mail-Plugin verwendet ein send_email-Binding. Registrieren und verifizieren Sie zuerst die Absenderdomain bei Cloudflare Email Sending. Cloudflare lehnt Nachrichten ab, deren From-Adresse kein akzeptierter Absender ist.
Fügen Sie das Binding hinzu und registrieren Sie den Provider:
{
"send_email": [{ "name": "EMAIL" }],
}
import { cloudflareEmail } from "@emdash-cms/cloudflare/plugins";
emdash({
plugins: [
cloudflareEmail({
from: { email: "[email protected]", name: "My Site CMS" },
replyTo: "[email protected]",
}),
],
}),
Das Plugin ist ab seiner ersten Bereitstellung aktiv. Settings → Email zeigt den ausgewählten Provider an und kann eine Test-E-Mail senden. Das Senden schlägt fehl, bis der Absender akzeptiert wird und das Binding existiert.
Das Plugin verwendet das Binding mit dem Namen EMAIL, sofern seine Option binding keinen anderen Namen angibt. Ist es der einzige aktive E-Mail-Provider, wählt EmDash es automatisch aus. Sind mehrere Provider aktiv, wählen Sie unter Settings → Email den Cloudflare-Provider. Die optionale Adresse replyTo empfängt Antworten, ohne die akzeptierte From-Adresse zu ändern. Ein Plugin kann replyTo für einzelne Nachrichten setzen, was diese Option für diese Nachricht überschreibt.
Cloudflare AI Search
Das AI-Search-Plugin benötigt sowohl eine native Plugin-Registrierung als auch ein ai_search_namespaces-Binding. Öffnen Sie nach der Bereitstellung Cloudflare AI Search in der Administration, wählen Sie die Collections aus und führen Sie Sync All Content aus. Die erste Synchronisierung indiziert Inhalte, die vor der Aktivierung des Plugins veröffentlicht wurden; Hooks halten spätere Änderungen synchron.
import { aiSearch } from "@emdash-cms/cloudflare/plugins";
emdash({
plugins: [aiSearch()],
}),
{
"ai_search_namespaces": [{ "binding": "AI_SEARCH", "namespace": "default" }],
}
Stellen Sie die Suchroute über die Site bereit:
export { POST, prerender } from "@emdash-cms/cloudflare/plugins/ai-search";
Fügen Sie die Suchoberfläche zu einem Layout hinzu. Der Trigger-Slot akzeptiert eine Schaltfläche, die zum Design der Site passt:
---
import AISearchSnippet from "@emdash-cms/cloudflare/plugins/ai-search/astro";
---
<AISearchSnippet apiUrl="/api/ai-search" placeholder="Search content">
<button slot="trigger" type="button">Search</button>
</AISearchSnippet>
Worker-Secrets
Speichern Sie geheime Werte mit pnpm wrangler secret put <NAME>. Legen Sie sie nicht in wrangler.jsonc ab und lesen Sie sie nicht aus import.meta.env-Werten zur Build-Zeit.
EMDASH_ENCRYPTION_KEY verschlüsselt Plugin-Einstellungen, die als Secrets deklariert sind. Setzen Sie ihn, bevor Sie ein Plugin-Secret speichern, und bewahren Sie ihn getrennt von D1-Backups auf. Geben Sie bei einer Rotation zuerst den neuen Schlüssel an und behalten Sie ältere Schlüssel hinter Kommas bei, bis jedes Plugin-Secret erneut gespeichert wurde. Secrets and key management beschreibt Rotation und Wiederherstellung.
Die Plugin-Bridge liest dieses Worker-Secret-Binding direkt. Die generierte Admin-Einstellungsroute liest es über process.env. Mit nodejs_compat füllt Cloudflare process.env standardmäßig für Kompatibilitätsdaten ab 2025-04-01. Projekte, die auf ein früheres Datum festgelegt sind, müssen vor dem Speichern verschlüsselter Einstellungen zusätzlich nodejs_compat_populate_process_env hinzufügen.
EmDash liest seine Secrets zur Laufzeit aus process.env. Worker-Code liest Bindings aus env, das aus cloudflare:workers importiert wird. Lesen Sie Secrets niemals über import.meta.env: Vite ersetzt diese Werte zur Build-Zeit und kann sie in das Server-Bundle schreiben.
Das Preview-HMAC-Secret und der Salt für Kommentierenden-IPs werden generiert und in der Datenbank gespeichert, sofern Sie keine Laufzeit-Overrides angeben. Secrets and key management listet die genauen Variablen, Speicherorte und Rotationsauswirkungen auf.
Preview-Bereitstellungen
Eine Preview kann als Worker Preview laufen, die jedem Branch eine eigene URL auf dem Produktions-Worker gibt, oder als separater Worker in einer benannten Wrangler-Umgebung. In beiden Fällen braucht die Preview eine von der Produktion getrennte Datenbank und einen eigenen Bucket. Richten Sie ein Preview-Binding niemals auf eine Produktionsdatenbank oder einen Produktions-Bucket.
Worker Previews
Worker Previews setzen Wrangler 4.135.0 oder neuer in den Abhängigkeiten des Projekts voraus. Projekte, die aus einem älteren EmDash-Template erstellt wurden, können eine frühere Version festschreiben; aktualisieren Sie sie mit pnpm add -D wrangler@latest. Previews erben weder Bindings noch vars aus der Konfiguration der obersten Ebene; führen Sie jedes Binding, das die Preview verwendet, in einem previews-Block auf.
Der Astro-Cloudflare-Adapter fügt ein KV-Binding SESSION hinzu. wrangler deploy richtet es automatisch ein, aber wrangler preview lehnt es ohne Namespace-ID ab. Legen Sie die Preview-Ressourcen an, einschließlich eines KV-Namespace für Sessions:
pnpm wrangler d1 create my-emdash-site-preview
pnpm wrangler r2 bucket create my-emdash-media-preview
pnpm wrangler kv namespace create my-emdash-site-preview-session
Tragen Sie die Ressourcenkennungen, die Wrangler ausgibt, in wrangler.jsonc ein:
{
"previews": {
"d1_databases": [
{
"binding": "DB",
"database_name": "my-emdash-site-preview",
"database_id": "00000000-0000-0000-0000-000000000000",
},
],
"r2_buckets": [
{
"binding": "MEDIA",
"bucket_name": "my-emdash-media-preview",
},
],
"kv_namespaces": [{ "binding": "SESSION", "id": "00000000000000000000000000000000" }],
"worker_loaders": [{ "binding": "LOADER" }],
},
}
Wiederholen Sie send_email, AI Search, vars und andere Bindings, wenn die Preview diese Funktionen nutzt.
Der Einrichtungsassistent und Passkeys benötigen die Site-URL der Preview. Ohne siteUrl oder EMDASH_SITE_URL scheitert die Einrichtung mit SITE_URL_REQUIRED. Übergeben Sie bei jeder Preview-Bereitstellung die Preview-URL, https://<preview-name>-<worker-name>.<subdomain>.workers.dev:
pnpm build
pnpm wrangler preview --name my-branch \
--var EMDASH_SITE_URL:https://my-branch-my-emdash-site.example.workers.dev
Verwenden Sie in --name und in der URL denselben Preview-Namen. Ein siteUrl in astro.config.mjs überschreibt EMDASH_SITE_URL und wird in jede Preview eingebaut, sodass Passkeys auf der Preview an die Produktionsdomain gebunden sind und dort weder Einrichtung noch Anmeldung funktionieren. Setzen Sie die Produktions-URL stattdessen mit EMDASH_SITE_URL in den vars der obersten Ebene.
Wenn der Worker workers_dev auf false setzt, haben Previews keine URL, bis Sie "preview_urls": true auf der obersten Ebene von wrangler.jsonc setzen und einmal wrangler deploy ausführen. wrangler preview wendet diese Einstellung nicht an. wrangler deploy veröffentlicht den Code Ihres aktuellen Checkouts in der Produktion, nicht nur die Einstellung. Committen Sie die Änderung daher und deployen Sie aus einem sauberen Checkout Ihres Produktions-Branches. Kehren Sie danach zu Ihrem Branch zurück und führen Sie wrangler preview erneut aus.
Setzen Sie ein Secret für eine einzelne Preview mit pnpm wrangler preview secret put <NAME> --name my-branch. pnpm wrangler preview base-config secret put <NAME> setzt ein Secret für danach erstellte Previews; bestehende Previews behalten ihre Secrets.
Beachten Sie diese Unterschiede zur Produktion:
- Previews teilen sich die Ressourcen im
previews-Block.wrangler previewliest denpreviews-Block des Branches, den es bereitstellt, daher verwendet jeder Branch, der die Konfiguration des Basis-Branches beibehält, dieselbe Datenbank. Die erste Anfrage an eine Preview wendet ausstehende Core-Migrationen an, sodass ein Branch, der EmDash aktualisiert, auch die Datenbank migriert, die die anderen Previews verwenden. Um einen Branch zu isolieren, legen Sie eine weitere D1-Datenbank an und ändern Sie vor der Bereitstellungdatabase_nameunddatabase_idimpreviews-Block dieses Branches. - Eine leere Preview-Datenbank zeigt den Einrichtungsassistenten. Preview-URLs sind öffentlich, und der erste Besucher, der den Assistenten abschließt, wird zum Administrator. Schließen Sie die Einrichtung unmittelbar nach dem Anlegen der Preview ab oder schützen Sie Preview-URLs mit Cloudflare Access.
- Cron Triggers laufen nicht. Geplante Beiträge werden nicht veröffentlicht, und Plugin-Cron-Aufgaben sowie geplante Backups laufen auf einer Preview nicht.
- Passkeys funktionieren nur auf dem Hostnamen, der sie registriert hat. Produktions-Passkeys funktionieren auf einer Preview nicht, und der auf der ersten Preview angelegte Administrator kann sich nur auf dieser Preview-URL mit einem Passkey anmelden. Melden Sie sich auf einer anderen Preview, die die Datenbank teilt, mit einem Magic Link an, der einen E-Mail-Anbieter und dessen Binding im
previews-Block benötigt, und fügen Sie dort einen Passkey hinzu. Alternativ isolieren Sie den Branch mit einer eigenen Datenbank, wie oben beschrieben, und führen Sie dort die Einrichtung aus.
Benannte Umgebungen
Benannte Wrangler-Umgebungen erben keine Bindings. Legen Sie separate Preview-Ressourcen an und schreiben Sie sie vor dem Build in die Umgebung preview:
pnpm wrangler d1 create my-emdash-site-preview \
--binding DB --env preview --update-config
pnpm wrangler r2 bucket create my-emdash-media-preview \
--binding MEDIA --env preview --update-config
Die Preview-Umgebung muss jedes Binding wiederholen, das der Preview-Worker verwendet. Die Core-Bindings für D1, R2 und Sandbox haben diese Form, nachdem Wrangler die Ressourcenkennungen geschrieben hat:
{
"env": {
"preview": {
"d1_databases": [
{
"binding": "DB",
"database_name": "my-emdash-site-preview",
"database_id": "00000000-0000-0000-0000-000000000000",
},
],
"r2_buckets": [
{
"binding": "MEDIA",
"bucket_name": "my-emdash-media-preview",
},
],
"worker_loaders": [{ "binding": "LOADER" }],
},
},
}
Verwenden Sie die von Wrangler geschriebene Preview-UUID. Wiederholen Sie optionale KV-, AI-Search-, E-Mail- und andere Bindings, wenn die Preview diese Funktionen nutzt. Fügen Sie Preview-spezifische Secrets mit pnpm wrangler secret put <NAME> --env preview hinzu.
Bauen Sie die Preview-Umgebung und stellen Sie sie bereit. Ihre erste Anfrage wendet ausstehende Core-Migrationen über den Standardmodus auto an.
pnpm build
pnpm wrangler deploy --env preview
Prüfen Sie vor dem Teilen die Preview-URL, die Admin-Anmeldung, den Medien-Upload und alle optionalen Bindings.
Bereitstellung überprüfen
Rufen Sie nach der Bereitstellung eine öffentliche Seite auf, melden Sie sich unter /_emdash/admin an, laden Sie eine Test-Mediendatei hoch und rufen Sie sie wieder ab, und bestätigen Sie, dass der scheduled-Handler in pnpm wrangler tail erscheint.
Fehlerbehebung
”D1 binding not found”
Prüfen Sie, ob der Binding-Name in wrangler.jsonc zu Ihrer Datenbankkonfiguration passt:
// Must match: d1({ binding: "DB" })
"binding": "DB"
“R2 binding not found”
Prüfen Sie, ob der R2-Bucket korrekt gebunden ist:
// Must match: r2({ binding: "MEDIA" })
"binding": "MEDIA"
Migrationsfehler
Wenn Sie Schemafehler sehen, verfolgen Sie die Worker-Logs (wrangler tail) und reproduzieren Sie den Fehler, um die zugrunde liegende Meldung zu erfassen – und melden Sie dann ein Issue mit dieser Ausgabe.