EmDash pour les développeurs Astro

Sur cette page

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

Ce qu’EmDash ajoute

FonctionnalitéCe qu’elle apporte
AdministrationGestion dans le navigateur des collections, des médias, des menus, des taxonomies et des paramètres à l’adresse /_emdash/admin
Collections en base de donnéesContenu géré par les éditeurs et interrogé au moment de la requête
MédiathèqueImages et fichiers stockés, avec des valeurs de champs média pour les modèles
Brouillons, révisions et aperçusTravail éditorial avant la publication
Menus et zones de widgetsRégions du site ordonnées et modifiables, en dehors des champs des entrées
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 facultatives de l’administration

Ces fonctionnalités coexistent avec Astro au lieu de le remplacer. Astro continue de gérer le routage, les mises en page, 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 du projetBase de données SQL
ÉditionWorkflow du dépôtAdministration EmDash
RequêtegetCollection()getEmDashCollection()
Texte enrichiMarkdown ou MDXPortable Text
LivraisonÀ la compilation ou via un loader en directLoader en direct à l’exécution

Utilisez les deux systèmes de collections lorsque la responsabilité du contenu diffère. Par exemple, le site d’un 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 modèles Node actuels configurent Astro pour une sortie serveur, ajoutent l’intégration EmDash et utilisent les adaptateurs SQLite et de 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 modèles Cloudflare configurés pour D1 et R2. Partez du modèle correspondant à la cible de déploiement plutôt que de convertir à la main les adaptateurs Node.

Enregistrer la collection en direct

Les modèles exposent le contenu EmDash via une seule 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 loader.

Interroger les collections

La requête suivante lit les articles publiés le plus récemment. orderBy utilise les noms de champs stockés et associe 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("Could not load posts", { 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 renvoient le contenu publié. Un filtre status explicite est utile dans du code authentifié ou compatible avec l’aperçu. where accepte les champs de contenu et les noms de taxonomies ; consultez Interroger le contenu pour les formes complètes des filtres et de la pagination.

Interroger une entrée

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

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

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

const { entry: post, error, cacheHint } = await getEmDashEntry("posts", slug);
if (error) return new Response("Could not load the post", { status: 500 });
if (!post) return Astro.rewrite("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---

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

L’entry.id renvoyé est l’identifiant de route d’Astro et correspond normalement au slug. L’ID de contenu en base de données est entry.data.id. Utilisez data.id avec les helpers qui exigent un ID de contenu stocké.

Utiliser les fonctionnalités CMS dynamiques

EmDash exporte des helpers 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 en bac à sable et les plugins natifs ont des structures de paquet différentes. Les plugins en bac à sable utilisent emdash-plugin.jsonc ainsi qu’un objet src/plugin.ts exporté par défaut. Les plugins natifs exportent une fabrique de descripteur et un createPlugin() construit avec definePlugin().

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

Prochaines étapes