Aller au contenu

Facultatif : Créer une collection de contenu

Maintenant que vous avez un blog utilisant le routage basé sur des fichiers intégré d’Astro, vous allez le mettre à jour pour utiliser une collection de contenu. Les collections de contenu sont un moyen puissant de gérer des groupes de contenu similaire, tels que des articles de blog.

Préparez-vous à…

  • Déplacez votre dossier d’articles de blog dans src/blog/
  • Créez un schéma pour définir le frontmatter de votre article de blog
  • Utilisez getCollection() pour obtenir le contenu et les métadonnées des articles de blog

Même lorsque vous utilisez des collections de contenu, vous utiliserez toujours le dossier src/pages/ pour les pages individuelles, telles que votre page À propos. Cependant, déplacer vos articles de blog en dehors de ce dossier spécial vous permettra d’utiliser des API plus puissantes et plus performantes pour générer l’index de vos articles de blog et afficher vos articles de blog individuels.

Dans le même temps, vous recevrez de meilleurs conseils et une meilleure saisie semi-automatique dans votre éditeur de code, car vous disposerez d’un schéma pour définir une structure commune pour chaque publication qu’Astro vous aidera à appliquer via Zod, une bibliothèque de déclaration de schéma et de validation pour TypeScript. Dans votre schéma, vous pouvez spécifier quand les propriétés du frontmatter sont requises, comme une description ou un auteur, et quel type de données doit être associé à chaque propriété, comme une chaîne de caractères ou un tableau. Cela permet de détecter de nombreuses erreurs plus tôt, avec des messages d’erreur descriptifs vous indiquant exactement quel est le problème.

Apprenez-en plus sur les collections de contenu d’Astro dans notre guide, ou commencez avec les instructions ci-dessous pour convertir un blog de base de src/pages/posts/ en src/blog/.

  1. Quel type de page conserveriez-vous probablement dans src/pages/ ?

  2. Lequel n’est pas un avantage de déplacer des articles de blog vers une collection de contenu ?

  3. Les collections de contenu utilisent TypeScript …

Les étapes ci-dessous vous montrent comment étendre le produit final du didacticiel Créer un blog en créant une collection de contenu pour les articles de blog.

Effectuez une mise à niveau vers la dernière version d’Astro et mettez à niveau toutes les intégrations vers leurs dernières versions en exécutant les commandes suivantes dans votre terminal :

Fenêtre du terminal
# Mettez à niveau Astro et les intégrations officielles ensemble
npx @astrojs/upgrade
  1. Créez une nouvelle collection (dossier) nommée src/blog/.

  2. Déplacez tous vos articles de blog existants (fichiers .md) de src/pages/posts/ vers cette nouvelle collection.

  3. Créez un fichier src/content.config.ts pour définir un schéma pour votre postsCollection. Pour le code existant du tutoriel de blog, ajoutez le contenu suivant au fichier pour définir toutes les propriétés de frontmatter utilisées dans ses articles de blog :

    src/content.config.ts
    // Importer le chargeur glob
    import { glob } from "astro/loaders";
    // Importer des utilitaires depuis `astro:content`
    import { z, defineCollection } from "astro:content";
    // Définir un chargeur (`loader`) et un schéma (`schema`) pour chaque collection
    const blog = defineCollection({
    loader: glob({ pattern: '**/[^_]*.md', base: "./src/blog" }),
    schema: z.object({
    title: z.string(),
    pubDate: z.date(),
    description: z.string(),
    author: z.string(),
    image: z.object({
    url: z.string(),
    alt: z.string()
    }),
    tags: z.array(z.string())
    })
    });
    // Exportez un seul objet `collections` pour enregistrer votre/vos collection(s)
    export const collections = { blog };
  4. Pour qu’Astro reconnaisse votre schéma, quittez (CTRL + C) et redémarrez le serveur de développement pour continuer le tutoriel. Cela définira le module astro:content.

Générer des pages à partir d’une collection

Titre de la section Générer des pages à partir d’une collection
  1. Créez un fichier de page appelé src/pages/posts/[...slug].astro. Vos fichiers Markdown et MDX ne deviennent plus automatiquement des pages utilisant le routage basé sur les fichiers d’Astro lorsqu’ils se trouvent dans une collection. Vous devez donc créer une page chargée de générer chaque article de blog individuel.

  2. Ajoutez le code suivant pour interroger votre collection afin de rendre le slug et le contenu de chaque page d’article de blog disponibles pour chaque page qu’elle générera :

    src/pages/posts/[...slug].astro
    ---
    import { getCollection, render } from 'astro:content';
    export async function getStaticPaths() {
    const posts = await getCollection('blog');
    return posts.map(post => ({
    params: { slug: post.id }, props: { post },
    }));
    }
    const { post } = Astro.props;
    const { Content } = await render(post);
    ---
  3. Rendez votre article avec <Content /> dans la mise en page pour les pages Markdown. Cela vous permet de spécifier une mise en page commune pour tous vos articles.

    src/pages/posts/[...slug].astro
    ---
    import { getCollection, render } from 'astro:content';
    import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';
    export async function getStaticPaths() {
    const posts = await getCollection('blog');
    return posts.map(post => ({
    params: { slug: post.id }, props: { post },
    }));
    }
    const { post } = Astro.props;
    const { Content } = await render(post);
    ---
    <MarkdownPostLayout frontmatter={post.data}>
    <Content />
    </MarkdownPostLayout>
  4. Supprimez la propriété layout dans le frontmatter de chaque article. Votre contenu est désormais enveloppé dans une mise en page lors du rendu, et cette propriété n’est plus nécessaire.

    src/content/posts/post-1.md
    ---
    layout: ../../layouts/MarkdownPostLayout.astro
    title: 'Mon premier article de blog'
    pubDate: 2022-07-01
    ...
    ---

Remplacez import.meta.glob() par getCollection()

Titre de la section Remplacez import.meta.glob() par getCollection()
  1. Partout où vous avez une liste d’articles de blog, comme la page Blog du tutoriel (src/pages/blog.astro/), vous devrez remplacer import.meta.glob() par getCollection() comme moyen de récupérer le contenu et les métadonnées de vos fichiers Markdown.

    src/pages/blog.astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../layouts/BaseLayout.astro";
    import BlogPost from "../components/BlogPost.astro";
    const pageTitle = "Mon blog d'apprentissage Astro";
    const allPosts = Object.values(import.meta.glob("../pages/posts/*.md", { eager: true }));
    const allPosts = await getCollection("blog");
    ---
  2. Vous devrez également mettre à jour les références aux données renvoyées pour chaque post. Vous trouverez maintenant les valeurs de votre frontmatter dans la propriété data de chaque objet. De plus, lors de l’utilisation de collections, chaque objet post aura un slug de page, et non une URL complète.

    src/pages/blog.astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../layouts/BaseLayout.astro";
    import BlogPost from "../components/BlogPost.astro";
    const pageTitle = "Mon blog d'apprentissage Astro";
    const allPosts = await getCollection("blog");
    ---
    <BaseLayout pageTitle={pageTitle}>
    <p>C'est ici que je publierai mon parcours d'apprentissage d'Astro.</p>
    <ul>
    {
    allPosts.map((post) => (
    <BlogPost url={post.url} title={post.frontmatter.title} />)}
    <BlogPost url={`/posts/${post.id}/`} title={post.data.title} />
    ))
    }
    </ul>
    </BaseLayout>
  3. Le projet de blog du tutoriel génère également dynamiquement une page pour chaque étiquette à l’aide de src/pages/tags/[tag].astro et affiche une liste des étiquettes dans src/pages/tags/index.astro.

    Appliquez les mêmes modifications que ci-dessus à ces deux fichiers :

    • récupérez des données sur tous vos articles de blog en utilisant getCollection("blog") au lieu d’utiliser import.meta.glob()
    • accédez à toutes les valeurs de frontmatter en utilisant data au lieu de frontmatter
    • créez une URL de page en ajoutant le slug de l’article au chemin /posts/

    La page qui génère des pages d’étiquettes individuelles devient désormais :

    src/pages/tags/[tag].astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../../layouts/BaseLayout.astro";
    import BlogPost from "../../components/BlogPost.astro";
    export async function getStaticPaths() {
    const allPosts = await getCollection("blog");
    const uniqueTags = [...new Set(allPosts.map((post) => post.data.tags).flat())];
    return uniqueTags.map((tag) => {
    const filteredPosts = allPosts.filter((post) =>
    post.data.tags.includes(tag)
    );
    return {
    params: { tag },
    props: { posts: filteredPosts },
    };
    });
    }
    const { tag } = Astro.params;
    const { posts } = Astro.props;
    ---
    <BaseLayout pageTitle={tag}>
    <p>Articles étiquetés avec {tag}</p>
    <ul>
    { posts.map((post) => <BlogPost url={`/posts/${post.id}/`} title={post.data.title} />) }
    </ul>
    </BaseLayout>

    Essayez-le vous-même - Mettez à jour la requête dans la page d’index des étiquettes

    Titre de la section Essayez-le vous-même - Mettez à jour la requête dans la page d’index des étiquettes

    Importez et utilisez getCollection pour récupérer les balises utilisées dans les articles de blog sur src/pages/tags/index.astro, en suivant les mêmes étapes que ci-dessus.

    Montrez-moi le code.
    src/pages/tags/index.astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../../layouts/BaseLayout.astro";
    const allPosts = await getCollection("blog");
    const tags = [...new Set(allPosts.map((post) => post.data.tags).flat())];
    const pageTitle = "Index des étiquettes";
    ---
    <!-- ... -->

Mettez à jour toutes les valeurs du frontmatter pour qu’elles correspondent à votre schéma

Titre de la section Mettez à jour toutes les valeurs du frontmatter pour qu’elles correspondent à votre schéma

Si nécessaire, mettez à jour toutes les valeurs du frontmatter de votre projet, comme dans votre mise en page, qui ne correspondent pas au schéma de vos collections.

Dans l’exemple du tutoriel du blog, pubDate était une chaîne de caractères. Désormais, selon le schéma qui définit les types pour le sujet de publication, pubDate sera un objet Date. Vous pouvez maintenant en profiter pour utiliser les méthodes disponibles pour n’importe quel objet Date pour formater la date.

Pour afficher la date dans la mise en page de l’article de blog, convertissez-la en chaîne de caractères à l’aide de la méthode toLocaleDateString() :

src/layouts/MarkdownPostLayout.astro
<!-- ... -->
<BaseLayout pageTitle={frontmatter.title}>
<p>{frontmatter.pubDate.toLocaleDateString()}</p>
<p><em>{frontmatter.description}</em></p>
<p>Écrit par : {frontmatter.author}</p>
<img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
<!-- ... -->

Le projet de blog du tutoriel comprend un flux RSS. Cette fonction doit également utiliser getCollection() pour renvoyer des informations à partir de vos articles de blog. Vous générerez ensuite les éléments RSS à l’aide de l’objet data renvoyé.

src/pages/rss.xml.js
import rss from '@astrojs/rss';
import { pagesGlobToRssItems } from '@astrojs/rss';
import { getCollection } from 'astro:content';
export async function GET(context) {
const posts = await getCollection("blog");
return rss({
title: 'Apprenti Astro | Blog',
description: "Mon parcours d'apprentissage d'Astro",
site: context.site,
items: await pagesGlobToRssItems(import.meta.glob('./**/*.md')),
items: posts.map((post) => ({
title: post.data.title,
pubDate: post.data.pubDate,
description: post.data.description,
link: `/posts/${post.id}/`,
})),
customData: `<language>fr-fr</language>`,
})
}

Pour l’exemple complet du tutoriel de blog utilisant des collections de contenu, consultez la branche Collections de contenu du dépôt du tutoriel.

Contribuer

Comment pouvons-nous vous aider ?

Créer une issue GitHub

Le moyen le plus rapide d'alerter notre équipe d'un problème.

Communauté