EmDash pour les développeurs Astro

Sur cette page

EmDash ajoute une application d’administration, des collections sauvegardées en base de données, des médias, des menus, des taxonomies, des paramètres, des révisions et des aperçus à un site Astro. Les pages et les composants restent des fichiers Astro ordinaires.

Ce qu’EmDash ajoute

FonctionnalitéCe qu’elle fournit
AdminGestion basée sur le navigateur des collections, médias, menus, taxonomies et paramètres à /_emdash/admin
Collections en base de donnéesContenu géré par l’éditeur interrogé au moment de la requête
Bibliothèque de médiasImages et fichiers stockés avec des valeurs de champs médias pour les templates
Brouillons, révisions et aperçusTravail éditorial avant publication
Menus et zones de widgetsRégions du site ordonnées et modifiables en dehors des champs d’entrée
Paramètres du siteValeurs d’identité et d’affichage partagées telles que le titre, le slogan, le logo et la taille de pagination
PluginsHooks, routes, stockage et extensions d’administration optionnelles

Ces fonctionnalités coexistent avec Astro plutôt que de le remplacer. Astro contrôle toujours le routage, les layouts, le rendu, les styles et l’adaptateur de déploiement.

EmDash et les collections Astro

Les collections de contenu Astro et les collections EmDash peuvent coexister. Utilisez les collections Astro pour le contenu appartenant au dépôt et EmDash pour le contenu géré via /_emdash/admin.

Collection de contenu AstroCollection EmDash
StockageFichiers dans le projetBase de données SQL
ÉditionFlux de travail du dépôtAdmin EmDash
RequêtegetCollection()getEmDashCollection()
Texte richeMarkdown ou MDXPortable Text
LivraisonCompilation ou chargeur en directChargeur en direct à l’exécution

Utilisez les deux systèmes de collections lorsque la propriété diffère. Par exemple, un site produit peut conserver les notes de version rédigées par les développeurs dans une collection de contenu Astro et les articles rédigés par les éditeurs dans EmDash :

---
import { getCollection } from "astro:content";
import { getEmDashCollection } from "emdash";

const [releaseNotes, { entries: articles }] = await Promise.all([
  getCollection("releases"),
  getEmDashCollection("articles", { limit: 3 }),
]);
---

Les deux résultats restent séparés. EmDash ne copie pas les entrées basées sur des fichiers dans sa base de données.

Configurer un site

Les templates Node actuels configurent Astro pour la sortie serveur, ajoutent l’intégration EmDash et utilisent les adaptateurs SQLite et stockage local.

La configuration réduite suivante contient ces éléments requis :

import node from "@astrojs/node";
import react from "@astrojs/react";
import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
  output: "server",
  adapter: node({ mode: "standalone" }),
  integrations: [
    react(),
    emdash({
      database: sqlite({ url: "file:./data.db" }),
      storage: local({
        directory: "./uploads",
        baseUrl: "/_emdash/api/media/file",
      }),
    }),
  ],
});

EmDash fournit également des templates Cloudflare configurés pour D1 et R2. Commencez avec le template correspondant à la cible de déploiement au lieu de traduire les adaptateurs Node manuellement.

Enregistrer la collection en direct

Les templates exposent le contenu EmDash via une collection en direct Astro nommée _emdash :

import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";

export const collections = {
  _emdash: defineLiveCollection({ loader: emdashLoader() }),
};

getEmDashCollection() et getEmDashEntry() sélectionnent le type de contenu demandé via ce chargeur.

Interroger les collections

La requête suivante lit les articles les plus récemment publiés. orderBy utilise les noms de champs stockés et mappe chaque nom à "asc" ou "desc" :

---
import { getEmDashCollection } from "emdash";

const { entries: posts, error, cacheHint } = await getEmDashCollection("posts", {
  orderBy: { published_at: "desc" },
  limit: 10,
});

if (error) return new Response("Impossible de charger les articles", { status: 500 });
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---

{posts.map((post) => (
  <article>
    <h2><a href={`/posts/${post.id}`}>{post.data.title}</a></h2>
  </article>
))}

Les requêtes anonymes retournent le contenu publié. Un filtre status explicite est utile dans le code authentifié ou avec aperçu. where accepte les champs de contenu et les noms de taxonomie ; voir Interroger le contenu pour les formes complètes de filtre et de pagination.

Interroger une entrée

Passez un slug ou un ID de base de données à getEmDashEntry(). La route suivante utilise son slug d’URL :

---
import { decodeSlug, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";

const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.redirect("/404");

const { entry: post, error, cacheHint } = await getEmDashEntry("posts", slug);
if (error) return new Response("Impossible de charger l'article", { status: 500 });
if (!post) return Astro.redirect("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---

<article>
  <h1>{post.data.title}</h1>
  <PortableText value={post.data.content} />
</article>

L’entry.id retourné est l’identifiant de route d’Astro et est normalement le slug. L’ID de contenu de la base de données est entry.data.id. Utilisez data.id avec les fonctions d’aide qui nécessitent un ID de contenu stocké.

Utiliser les fonctionnalités CMS dynamiques

EmDash exporte des fonctions d’aide serveur pour les données qui n’appartiennent pas à une seule entrée de collection :

---
import { getMenu, getSiteSettings } from "emdash";
import { WidgetArea } from "emdash/ui";

const [menu, settings] = await Promise.all([
  getMenu("primary"),
  getSiteSettings(),
]);
---

<header>
  <a href="/">{settings.title}</a>
  <nav>
    {menu?.items.map((item) => <a href={item.url}>{item.label}</a>)}
  </nav>
</header>

<main><slot /></main>
<aside><WidgetArea name="sidebar" /></aside>

Choisir un format de plugin

Les plugins sandboxed et natifs ont des structures de paquets différentes. Les plugins sandboxed utilisent emdash-plugin.jsonc plus un objet src/plugin.ts exporté par défaut. Les plugins natifs exportent une factory de descripteur et createPlugin() construit avec definePlugin().

Lisez Choisir un format de plugin avant d’ajouter un plugin. Ne copiez pas un exemple natif definePlugin() dans un paquet sandboxed.

Prochaines étapes