Aller au contenu

Tutoriel - Étendre avec les collections de contenu

Les collections de contenu sont un moyen puissant de gérer des groupes de contenus similaires, tels que des articles de blog. Les collections permettent d’organiser vos documents, de valider votre frontmatter YAML et de fournir une sécurité de type TypeScript automatique pour l’ensemble de votre contenu (même si vous n’écrivez pas de TypeScript vous-même).

Préparez-vous à…

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

Vous aurez besoin d’un projet Astro existant avec des fichiers Markdown ou MDX dans le dossier src/pages/.

Ce tutoriel utilise le projet fini du tutoriel Construire un blog pour démontrer la conversion d’un blog en collections de contenus. Vous pouvez forker et utiliser cette base de code localement, ou compléter le tutoriel dans le navigateur en éditant le code du tutoriel sur les blogs dans StackBlitz.

Vous pouvez également suivre ces étapes avec votre propre projet Astro, mais vous devrez adapter les instructions à votre base de code.

Nous vous recommandons d’utiliser notre exemple de projet pour compléter ce court tutoriel dans un premier temps. Ensuite, vous pourrez utiliser ce que vous avez appris pour créer des collections de contenu dans votre propre projet.

Dans le Tutoriel d’introduction à la création d’un blog, vous avez découvert le routage intégré basé sur les fichiers d’Astro : tout fichier .astro, .md, ou .mdx situé dans le dossier src/pages/ devient automatiquement une page de votre site.

Pour créer votre premier article de blog à https://exemple.com/posts/post-1/, vous avez créé un dossier /posts/ et ajouté le fichier post-1.md. Vous avez ensuite ajouté un nouveau fichier Markdown à ce dossier chaque fois que vous vouliez ajouter un nouvel article de blog à votre site.

Même si vous utilisez des collections de contenus, vous utiliserez toujours le dossier src/pages/ pour les pages individuelles, comme votre page À propos de moi. Mais en déplaçant vos articles de blog vers le dossier spécial src/content/, vous pourrez utiliser des API plus puissantes et plus performantes pour générer l’index de vos articles de blog et afficher vos articles individuels.

En même temps, vous recevrez de meilleurs conseils et une autocomplétion dans votre éditeur de code parce que vous aurez un schéma pour définir une structure commune pour chaque article qu’Astro vous aidera à mettre en application. Dans votre schéma, vous pouvez spécifier quand des propriétés sont requises, comme une description ou un auteur, et quel type de données chaque propriété doit être, comme une chaîne ou un tableau. De nombreuses erreurs sont ainsi détectées plus rapidement, et des messages d’erreur descriptifs vous indiquent exactement la nature du problème.

Pour en savoir plus sur les collections de contenu Astro, lisez notre guide, ou commencez avec les instructions ci-dessous pour convertir un blog basique de src/pages/posts/ à src/content/posts/.

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

  2. Quel n’est pas l’avantage de déplacer les articles de blog vers une collection de contenus ?

  3. Les collections de contenu utilisent TypeScript…

Extension du tutoriel sur le blog avec des collections de contenus

Titre de la section Extension du tutoriel sur le blog avec des collections de contenus

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

  1. Mettez à jour la dernière version d’Astro, et mettez à jour toutes les intégrations vers leurs dernières versions en exécutant les commandes suivantes dans votre terminal :

    Fenêtre de terminal
    # Mettre à jour Astro v4.x
    npm install astro@latest
    # Exemple : mise à jour du tutoriel du blog Intégration de Preact
    npm install @astrojs/preact@latest
  2. Le tutoriel du blog utilise le paramètre TypeScript base (le moins strict). Pour utiliser les collections de contenus, vous devez configurer TypeScript pour les collections de contenus soit en utilisant le paramètre strict ou strictest, soit en ajoutant deux options dans tsconfig.json.

    Afin d’utiliser les collections de contenu sans écrire de TypeScript dans le reste de l’exemple du tutoriel du blog, ajoutez les deux options de configuration TypeScript suivantes au fichier de configuration :

    tsconfig.json
    {
    // Note : Aucun changement n'est nécessaire si vous utilisez "astro/tsconfigs/strict" ou "astro/tsconfigs/strictest".
    "extends": "astro/tsconfigs/base",
    "compilerOptions": {
    "strictNullChecks": true,
    "allowJs": true
    }
    }

Créer une collection pour vos articles de blog

Titre de la section Créer une collection pour vos articles de blog
  1. Créez une nouvelle collection (dossier) appelée src/content/posts/.

  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 du tutoriel de blog existant, ajoutez le contenu suivant au fichier pour définir toutes les propriétés frontmatter utilisées dans ses articles de blog :

    src/content/config.ts
    // Importe les propriétés depuis `astro:content`
    import { z, defineCollection } from "astro:content";
    // Définir un `type` et un `schema` pour chaque collection
    const postsCollection = defineCollection({
    type: 'content',
    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())
    })
    });
    // Exporter un objet `collections` unique pour y enregistrer vos collections
    export const collections = {
    posts: postsCollection,
    };
  4. Pour qu’Astro reconnaisse votre schéma, quittez le serveur de développement (CTRL + C) et exécutez la commande suivante : npx astro sync. Ceci définira le module astro:content pour l’API Content Collections. Redémarrez le serveur de développement pour continuer le tutoriel.

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 en utilisant le routage basé sur les fichiers d’Astro lorsqu’ils se trouvent dans une collection, vous devez donc créer une page responsable de la génération de chaque article de blog.

  2. Ajoutez le code suivant pour interroger votre collection pour que le slug de chaque article de blog et le contenu de la page soient disponibles pour chaque page qu’il génèrera :

    src/pages/posts/[...slug].astro
    ---
    import { getCollection } from 'astro:content';
    import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';
    export async function getStaticPaths() {
    const blogEntries = await getCollection('posts');
    return blogEntries.map(entry => ({
    params: { slug: entry.slug }, props: { entry },
    }));
    }
    const { entry } = Astro.props;
    const { Content } = await entry.render();
    ---
  3. Rendre le <Content /> de l’article avec 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 } from 'astro:content';
    import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';
    export async function getStaticPaths() {
    const blogEntries = await getCollection('posts');
    return blogEntries.map(entry => ({
    params: { slug: entry.slug }, props: { entry },
    }));
    }
    const { entry } = Astro.props;
    const { Content } = await entry.render();
    ---
    <MarkdownPostLayout frontmatter={entry.data}>
    <Content />
    </MarkdownPostLayout>
  4. Supprimez la définition de layout dans le frontmatter de chaque article. Votre contenu est maintenant enveloppé dans un layout 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
    ...
    ---

Remplacer Astro.glob() avec getCollection()

Titre de la section Remplacer Astro.glob() avec 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 Astro.glob() par getCollection() comme moyen d’extraire 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 pour apprendre Astro";
    const allPosts = await Astro.glob("../pages/posts/*.md");
    const allPosts = await getCollection("posts");
    ---
  2. Vous devrez également mettre à jour les références aux données retournées pour chaque post. Vous trouverez maintenant vos valeurs frontmatter dans la propriété data de chaque objet. De plus, lorsque vous utilisez des collections, chaque objet post aura un slug de page, et non pas 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 pour apprendre Astro";
    const allPosts = await getCollection("posts");
    ---
    <BaseLayout pageTitle={pageTitle}>
    <p>C'est ici que j'écrirai sur mon parcours d'apprentissage d'Astro.</p>
    <ul>
    {
    allPosts.map((post) => (
    <BlogPost url={post.url} title={post.frontmatter.title} />)}
    <BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />
    ))
    }
    </ul>
    </BaseLayout>
  3. Le tutoriel du projet de blog génère aussi dynamiquement une page pour chaque tag en utilisant src/pages/tags/[tag].astro et affiche une liste de tag dans src/pages/tags/index.astro.

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

    • récupérer les données de tous les articles de votre blog en utilisant getCollection("posts") au lieu d’utiliser Astro.glob()
    • accéder à toutes les valeurs de frontmatter en utilisant data au lieu de frontmatter
    • créer une URL de page en ajoutant le slug de l’article au chemin /posts/.

    La page qui génère les pages de tags individuels devient maintenant :

    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("posts");
    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>Article contenant le tag {tag}</p>
    <ul>
    { posts.map((post) => <BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />) }
    </ul>
    </BaseLayout>

    Essayez vous-même - Mettez à jour la requête dans la page Tag Index

    Titre de la section Essayez vous-même - Mettez à jour la requête dans la page Tag Index

    Importez et utilisez getCollection pour récupérer les tags utilisés dans les articles du 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("posts");
    const tags = [...new Set(allPosts.map((post) => post.data.tags).flat())];
    const pageTitle = "Tag Index";
    ---
    ...

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

Titre de la section Mettez à jour les valeurs du frontmatter pour qu’elles correspondent à votre schéma.
  1. Si nécessaire, mettez à jour toutes les valeurs frontmatter dans votre projet, comme dans votre mise en page, qui ne correspondent pas à votre schéma de collections.

    Dans l’exemple du tutoriel sur les blogs, pubDate était une chaîne de caractères. Maintenant, selon le schéma qui définit les types pour le frontmatter post, pubDate sera un objet Date

    Pour rendre la date dans la mise en page de l’article de blog, convertissez-la en chaîne de caractères :

    src/layouts/MarkdownPostLayout.astro
    ...
    <BaseLayout pageTitle={frontmatter.title}>
    <p>{frontmatter.pubDate.toString().slice(0,10)}</p>
    <p><em>{frontmatter.description}</em></p>
    <p>Écrit par: {frontmatter.author}</p>
    <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    ...
  1. Enfin, le projet tutoriel de blog inclut un flux RSS. Cette fonction doit également utiliser getCollection() pour renvoyer des informations sur les articles de votre 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("posts");
    return rss({
    title: 'Apprendre Astro | Blog',
    description: 'Ma journée pour apprendre 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.slug}/`,
    })),
    customData: `<language>fr-fr</language>`,
    })
    }

Pour un exemple complet du tutoriel sur les blogs utilisant des collections de contenus, voir la branche Collections de contenus du répertoire du tutoriel.