EmDash fournit des fonctions de requête pour récupérer du contenu dans vos pages et composants Astro. Ces fonctions suivent le pattern des live content collections d’Astro, retournant des résultats structurés avec gestion d’erreurs.
Fonctions de requête
EmDash exporte deux fonctions de requête principales :
| Fonction | Objectif | Retourne |
|---|---|---|
getEmDashCollection | Récupérer toutes les entrées d’un type de contenu | { entries, error } |
getEmDashEntry | Récupérer une entrée par ID ou slug | { entry, error, isPreview } |
Importez-les depuis emdash :
import { getEmDashCollection, getEmDashEntry } from "emdash";
Obtenir toutes les entrées
Utilisez getEmDashCollection pour récupérer toutes les entrées d’un type de contenu :
---
import { getEmDashCollection } from "emdash";
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) {
console.error("Échec du chargement des articles :", error);
}
---
<ul>
{posts.map((post) => (
<li>{post.data.title}</li>
))}
</ul>
Filtrer par locale
Quand l’i18n est activée, filtrez par locale pour récupérer du contenu dans une langue spécifique :
const { entries: frenchPosts } = await getEmDashCollection("posts", {
locale: "fr",
status: "published",
});
const { entries: localizedPosts } = await getEmDashCollection("posts", {
locale: Astro.currentLocale,
status: "published",
});
Pour les entrées individuelles, passez locale comme troisième argument :
const { entry: post } = await getEmDashEntry("posts", "my-post", {
locale: Astro.currentLocale,
});
Quand locale est omis, il utilise par défaut le locale de la requête actuelle. Si aucune traduction n’existe pour le locale demandé, la chaîne de repli est suivie.
Filtrer par statut
Récupérer uniquement le contenu publié ou brouillon :
const { entries: published } = await getEmDashCollection("posts", {
status: "published",
});
const { entries: drafts } = await getEmDashCollection("posts", {
status: "draft",
});
Limiter les résultats
const { entries: recentPosts } = await getEmDashCollection("posts", {
status: "published",
limit: 5,
});
Filtrer par taxonomie
const { entries: newsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { category: "news" },
});
const { entries: jsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { tag: "javascript" },
});
const { entries: featuredNews } = await getEmDashCollection("posts", {
status: "published",
where: { category: ["news", "featured"] },
});
Le filtre where utilise la logique OU lorsque plusieurs valeurs sont fournies pour une seule taxonomie.
Gestion d’erreurs
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) {
console.error("Échec du chargement des articles :", error);
return new Response("Erreur serveur", { status: 500 });
}
Obtenir une entrée unique
---
import { getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
const { slug } = Astro.params;
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) {
return new Response("Erreur serveur", { status: 500 });
}
if (!post) {
return Astro.redirect("/404");
}
---
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
Type de retour d’entrée
interface EntryResult<T> {
entry: ContentEntry<T> | null;
error?: Error;
isPreview: boolean;
}
interface ContentEntry<T> {
id: string;
data: T;
edit: EditProxy;
}
Rendre les données du panneau SEO
Pour les collections avec supports: ["seo"], les éditeurs peuvent définir un titre SEO, une meta description, une image OG, une URL canonique et un toggle « masquer des moteurs de recherche » (noindex) dans le panneau SEO de l’admin. Ces données sont livrées sur l’entrée comme entry.data.seo — mais elles n’atteignent la page rendue que si votre template les émet. Utilisez getSeoMeta pour résoudre les champs du panneau (avec des replis sensés vers data.title / data.excerpt) en meta tags prêts à rendre :
---
import { getEmDashEntry, getSeoMeta } from "emdash";
const { entry, error } = await getEmDashEntry("posts", Astro.params.slug);
if (error) {
return new Response("Erreur serveur", { status: 500 });
}
if (!entry) return Astro.redirect("/404");
const seo = getSeoMeta(entry, {
siteTitle: "Mon Site",
siteUrl: "https://example.com",
path: Astro.url.pathname,
});
---
<head>
<title>{seo.title}</title>
{seo.description && <meta name="description" content={seo.description} />}
{seo.ogImage && <meta property="og:image" content={seo.ogImage} />}
{seo.canonical && <link rel="canonical" href={seo.canonical} />}
{seo.robots && <meta name="robots" content={seo.robots} />}
</head>
Mode aperçu
EmDash gère l’aperçu automatiquement via le middleware. Quand une URL contient un token _preview valide, le middleware le vérifie et configure le contexte de requête. Vos fonctions de requête servent alors le contenu brouillon sans paramètres spéciaux :
---
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
const { entry, isPreview, error } = await getEmDashEntry("posts", slug);
if (error) {
return new Response("Erreur serveur", { status: 500 });
}
if (!entry) {
return Astro.redirect("/404");
}
---
{isPreview && (
<div class="preview-banner">
Visualisation de l'aperçu. Ce contenu n'est pas publié.
</div>
)}
<article>
<h1>{entry.data.title}</h1>
<PortableText value={entry.data.content} />
</article>
Édition visuelle
Chaque entrée retournée par les fonctions de requête inclut un proxy edit pour annoter vos templates. Étalez-le sur les éléments pour activer l’édition inline pour les éditeurs authentifiés :
<article {...entry.edit}>
<h1 {...entry.edit.title}>{entry.data.title}</h1>
<div {...entry.edit.content}>
<PortableText value={entry.data.content} />
</div>
</article>
En mode édition, {...entry.edit.title} produit un attribut data-emdash-ref que la barre d’outils d’édition visuelle utilise pour l’édition inline. En production, les spreads du proxy ne produisent aucune sortie.
Styler les blocs de code inline
Les blocs de code inline suivent l’apparence claire ou sombre du système par défaut. Si votre site a son propre interrupteur de thème, définissez ces propriétés dans ses sélecteurs de thème clair et sombre :
| Propriété | Objectif |
|---|---|
--emdash-inline-code-background | Fond du bloc de code |
--emdash-inline-code-foreground | Texte de code simple |
--emdash-inline-code-muted | Commentaires et texte cité |
--emdash-inline-code-keyword | Mots-clés, littéraux, sélecteurs et texte supprimé |
--emdash-inline-code-string | Chaînes, attributs, symboles et texte ajouté |
--emdash-inline-code-number | Nombres et métadonnées |
--emdash-inline-code-title | Titres, noms, types et built-ins |
--emdash-inline-code-border | Bordure du sélecteur de langue |
--emdash-inline-code-control-background | Fond du sélecteur de langue |
--emdash-inline-code-control-foreground | Texte et icônes du sélecteur de langue |
--emdash-inline-code-focus | Indicateur de focus clavier |
:root {
--emdash-inline-code-background: #f7f7f5;
--emdash-inline-code-foreground: #24292f;
--emdash-inline-code-muted: #57606a;
--emdash-inline-code-keyword: #b8172a;
--emdash-inline-code-string: #0a3069;
--emdash-inline-code-number: #0550ae;
--emdash-inline-code-title: #7545c7;
--emdash-inline-code-border: #7d8590;
--emdash-inline-code-control-background: #fff;
--emdash-inline-code-control-foreground: #24292f;
--emdash-inline-code-focus: #0550ae;
}
:root.dark {
--emdash-inline-code-background: #202020;
--emdash-inline-code-foreground: #f0f3f6;
--emdash-inline-code-muted: #c9d1d9;
--emdash-inline-code-keyword: #ffc1bb;
--emdash-inline-code-string: #b9ddff;
--emdash-inline-code-number: #a8d5ff;
--emdash-inline-code-title: #e5ccff;
--emdash-inline-code-border: #6e7681;
--emdash-inline-code-control-background: #161b22;
--emdash-inline-code-control-foreground: #f0f3f6;
--emdash-inline-code-focus: #a8d5ff;
}
Si vous changez le fond du bloc de code, remplacez aussi chaque couleur de texte pour que la syntaxe reste lisible. Ces propriétés ne s’appliquent que pendant l’édition inline. Stylez les blocs de code publiés avec le CSS de votre site.
Trier les résultats
getEmDashCollection ne garantit pas l’ordre de tri. Triez les résultats dans votre template :
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
const sorted = posts.sort(
(a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0),
);
Patterns de tri courants
posts.sort((a, b) => a.data.title.localeCompare(b.data.title));
posts.sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0));
posts.sort(() => Math.random() - 0.5);
Types TypeScript
Générez des types TypeScript pour vos collections :
npx emdash types
Cela crée .emdash/types.ts avec des interfaces pour chaque collection :
import { getEmDashCollection, getEmDashEntry } from "emdash";
import type { Post } from "../.emdash/types";
const { entries: posts } = await getEmDashCollection<Post>("posts");
const { entry: post } = await getEmDashEntry<Post>("posts", "my-post");
Rendu statique vs. serveur
Statique (Pré-rendu)
---
import { getEmDashCollection, getEmDashEntry } from "emdash";
export async function getStaticPaths() {
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
return posts.map((post) => ({
params: { slug: post.data.slug },
}));
}
const { slug } = Astro.params;
const { entry: post } = await getEmDashEntry("posts", slug);
---
Rendu serveur
---
export const prerender = false;
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) {
return new Response("Erreur serveur", { status: 500 });
}
if (!post) {
return new Response(null, { status: 404 });
}
---
Considérations de performance
Cache
EmDash utilise les live content collections d’Astro, qui gèrent le cache automatiquement. Pour les pages rendues côté serveur, ajoutez des en-têtes de cache HTTP :
---
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
Astro.response.headers.set("Cache-Control", "public, max-age=300");
---
Éviter les requêtes redondantes
---
import { getEmDashCollection } from "emdash";
import PostList from "../components/PostList.astro";
import Sidebar from "../components/Sidebar.astro";
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
const featured = posts.filter((p) => p.data.featured);
const recent = posts.slice(0, 5);
---
<PostList posts={featured} />
<Sidebar posts={recent} />
Prochaines étapes
- Créer un blog - Construire un blog complet
- Taxonomies - Filtrer par catégories et tags
- Travailler avec le contenu - Opérations CRUD admin
- Internationalisation - Contenu multilingue et traductions