Le template de blog EmDash fournit un site Astro fonctionnel avec des articles, pages, auteurs, catégories, tags, recherche, commentaires, widgets et un flux RSS. Ce tutoriel crée la version Cloudflare, publie un article et trace cet article à travers le code du template.
Prérequis
Installez Node.js 22.12 ou ultérieur et pnpm avant de commencer.
Vous n’avez besoin d’un compte Cloudflare que lors du déploiement du site. Pendant le développement local, le template exécute des versions locales de la base de données et du stockage de fichiers sur votre ordinateur.
Créer la structure du blog
La commande suivante crée my-blog à partir du template de blog Cloudflare et installe ses dépendances avec pnpm :
npm create emdash@latest my-blog -- --template cloudflare:blog --pm pnpm --yes
Le scaffolder crée aussi un fichier .env local avec un EMDASH_ENCRYPTION_KEY. Le .gitignore généré exclut .env du contrôle de version. Si la commande signale que l’installation des dépendances a échoué, entrez dans le répertoire du projet et exécutez pnpm install avant de continuer.
Démarrez le serveur de développement local :
cd my-blog
pnpm dev
Ouvrez l’URL locale affichée dans le terminal, puis ouvrez /_emdash/admin. Complétez l’écran de configuration si c’est le premier lancement. Les données de seed du template créent le modèle de contenu et le contenu exemple lors de la configuration.
Comprendre le modèle de contenu
Le template définit deux collections dans seed/seed.json :
postsactive les brouillons, révisions, recherche et SEO viasupports, et active les commentaires séparément aveccommentsEnabled: true;pagessupporte les brouillons, révisions et la recherche.
Chaque article a ces champs personnalisés :
| Champ | Objectif |
|---|---|
title | Titre d’article obligatoire |
featured_image | Image optionnelle affichée avec l’article |
content | Corps en Portable Text |
excerpt | Texte court utilisé dans les listes d’articles et les fallbacks de métadonnées |
EmDash ajoute des champs système comme l’ID de contenu stable, le slug, le statut, les dates de création et mise à jour, et la date de publication. Le template définit aussi des taxonomies category et tag pour les articles, plus des signatures d’auteur pouvant créditer un ou plusieurs auteurs.
Le serveur de dev génère emdash-env.d.ts à partir de ce schéma. En conséquence, getEmDashCollection("posts") retourne des entrées dont la propriété data est typée comme Post.
Publier le premier article
-
Dans la barre latérale de l’admin, sélectionnez Posts, puis Add New.
-
Entrez un titre. EmDash suggère un slug à partir du titre ; modifiez-le si l’URL publique nécessite une valeur différente.
-
Ajoutez un extrait et rédigez le corps dans l’éditeur Content.
-
Sélectionnez une image à la une depuis la Bibliothèque de Médias ou téléchargez-en une. Ajoutez un texte alternatif décrivant le rôle de l’image dans l’article.
-
Assignez une signature d’auteur, une catégorie et des tags pertinents dans le panneau de paramètres.
-
Sélectionnez Save. L’entrée devient un brouillon et l’éditeur ouvre son URL permanente.
-
Sélectionnez Preview et vérifiez la page de l’article. Retournez à l’éditeur et sélectionnez Publish quand le brouillon est prêt.
Ouvrez /posts/your-post-slug sur le site local. L’article apparaît aussi sur la page d’accueil et l’archive des articles. S’il n’apparaît pas, confirmez que l’éditeur affiche Published, pas Draft ou Scheduled.
Après publication, les modifications s’enregistrent automatiquement dans un nouveau brouillon tandis que l’article actuel reste en ligne. Sélectionnez Publish changes quand le brouillon révisé doit le remplacer. Le guide de rédaction de contenu explique les prévisualisations, la programmation, les révisions et les verrous d’édition.
Suivre la requête de collection
La page d’accueil et l’archive d’articles appellent getEmDashCollection() pendant le rendu serveur. Le template ordonne les articles dans la base de données par le champ published_at :
---
import { getEmDashCollection, getTermsForEntries } from "emdash";
const { entries: posts, cacheHint } = await getEmDashCollection("posts", {
orderBy: { published_at: "desc" },
});
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
const tagsByEntry = await getTermsForEntries(
"posts",
posts.map((post) => post.data.id),
"tag",
);
---
La requête de collection retourne les entrées publiées par défaut. Elle utilise published_at, le nom du champ de la base de données, pour le tri. La propriété publishedAt retournée est un Date JavaScript pour le rendu.
Le helper de taxonomie reçoit post.data.id car les assignations de taxonomie appartiennent à l’ID de contenu stable. Les liens utilisent post.id à la place, car c’est le slug orienté URL produit par le content loader :
<a href={`/posts/${post.id}`}>
<h2>{post.data.title}</h2>
{post.data.excerpt && <p>{post.data.excerpt}</p>}
</a>
Le template actuel regroupe les recherches de tags avec getTermsForEntries() au lieu de requêter une fois par article. Les signatures d’auteur sont déjà incluses dans post.data.bylines par la requête de collection.
Suivre la requête d’article
La route dynamique d’article lit le slug depuis l’URL et appelle getEmDashEntry(). L’extrait suivant montre la requête essentielle et le chemin de rendu, tandis que le template complet gère aussi le SEO, les signatures, les commentaires, les articles connexes et les widgets :
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { Image, 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("Unable to load post", { status: 500 });
if (!post) return Astro.redirect("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---
<article>
{post.data.featured_image && <Image image={post.data.featured_image} priority />}
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
Image lit la valeur média sélectionnée par l’éditeur et génère une sortie responsive. PortableText transforme les données de bloc stockées en titres, paragraphes, liens, images, blocs de code et les autres types de blocs supportés.
Les deux templates de blog définissent output: "server" dans astro.config.mjs. Ces requêtes s’exécutent quand une requête est rendue, donc le contenu publié ne dépend pas d’une liste de routes statiques créée pendant le build.
Utiliser les catégories et tags
Le template inclut des routes d’archive pour chaque catégorie et tag. Une route de catégorie résout d’abord le slug du terme, puis filtre les articles par cette taxonomie :
---
import { decodeSlug, getEmDashCollection, getTerm } from "emdash";
const slug = decodeSlug(Astro.params.slug);
const category = slug
? await getTerm("category", slug, { includeCounts: false })
: null;
if (!category) return Astro.redirect("/404");
const { entries: posts, error } = await getEmDashCollection("posts", {
where: { category: category.slug },
orderBy: { published_at: "desc" },
});
if (error) return new Response("Unable to load posts", { status: 500 });
---
La route tag utilise le même pattern avec getTerm("tag", slug) et where: { tag: term.slug }. Les rédacteurs gèrent les termes et assignations dans l’admin ; le guide des Taxonomies couvre les catégories hiérarchiques, les tags plats et les taxonomies personnalisées.
getEmDashEntry() inclut les termes assignés de l’article, donc la route de détail peut les rendre sans autre requête :
---
const categories = post.data.terms?.category ?? [];
const tags = post.data.terms?.tag ?? [];
---
{categories.map((category) => (
<a href={`/category/${category.slug}`}>{category.label}</a>
))}
{tags.map((tag) => (
<a href={`/tag/${tag.slug}`}>{tag.label}</a>
))}
Ajouter la pagination de l’archive
L’archive d’articles du template rend chaque article publié. Quand l’archive grandit, ajoutez un limit et utilisez la pagination par offset pour des routes numérotées comme /posts/page/2, ou la pagination par curseur pour un lien Articles plus anciens. Gardez orderBy: { published_at: "desc" } inchangé entre les pages pour que les entrées ne changent pas d’ordre de façon inattendue.
Les exemples de pagination montrent les deux approches et expliquent quand choisir chacune.
Vérifier le flux RSS
Le template sert déjà /rss.xml. Son endpoint lit les 20 articles les plus récents avec getEmDashCollection(), formate chaque date de publication et échappe le titre et l’extrait avant de les insérer dans le XML. Il lit aussi le titre du site et le slogan depuis les paramètres EmDash.
Après avoir publié l’article de test, ouvrez /rss.xml et cherchez son titre. Si le site utilisera une URL de production absolue dans les flux, définissez l’option site d’Astro avant le déploiement ; l’endpoint se rabat sur l’origine de la requête actuelle pendant le développement local.
À ce stade, le blog dispose d’un workflow de rédaction, de pages d’articles en temps réel, d’archives par taxonomie, de rendu de médias et d’un flux. Continuez avec Interroger le Contenu pour les filtres et la pagination, ou Bibliothèque de Médias pour l’édition d’assets et le suivi d’utilisation. Pour rédiger ou modifier des articles avec un assistant IA, suivez Outils IA.