Implémenter l'index du blog avec VitePress et Tailwind CSS

- Read in english
Ressources: garabit

Avant de plonger dans la tâche principale, nous devons configurer Tailwind CSS. Cette étape, bien que simple, est essentielle pour styliser notre blog.

Configuration de Tailwind CSS

Nous devons indiquer à Tailwind CSS où se trouvent nos fichiers. Dans le fichier tailwind.config.cjs à la racine du projet, utilisons la clé content pour spécifier quels fichiers analyser afin de générer les classes CSS nécessaires.

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.md', './.vitepress/theme/**/*.{vue,ts}'],
  // ...
}

Nous indiquons à Tailwind CSS de scanner à la fois les fichiers Markdown et tous les fichiers Vue et TypeScript dans le répertoire du thème.

Note

La surveillance des fichiers Markdown est cruciale puisqu'ils peuvent contenir du HTML, et des composants peuvent également y être inclus.

Intégration de Prettier avec le Plugin Tailwind CSS

De plus, nous allons configurer Prettier pour le formatage du code et ajouter le plugin Prettier Tailwind CSS pour trier automatiquement les classes.

Pour installer Prettier et le plugin, exécutons :

sh
pnpm add -D prettier prettier-plugin-tailwindcss

Créons un fichier .prettierrc à la racine du projet avec la configuration suivante :

json
{
  "plugins": ["prettier-plugin-tailwindcss"]
}

Si vous utilisez Visual Studio Code, incluez ce qui suit dans .vscode/settings.json pour activer le formatage automatique à l'enregistrement :

json
{
  "prettier.enable": true,
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

Ajoutons un script dans package.json pour formater les fichiers avec Prettier :

json
{
  "scripts": {
    "format": "prettier --write ."
  }
}

Connexion de Tailwind CSS au Projet

Enfin, nous devons lier notre projet au CSS généré par Tailwind CSS. Dans .vitepress/theme/styles, créons un fichier app.css et ajoutons-y les directives Tailwind CSS :

css
@tailwind base;
@tailwind components;
@tailwind utilities;

Ensuite, importons ce fichier dans .vitepress/theme/index.ts :

ts
import { Theme } from 'vitepress'
import Layout from './Layout.vue'

import './styles/app.css'

export default {
  Layout,
} satisfies Theme

L'importation d'un fichier CSS directement dans un fichier TypeScript ne pose aucun problème car Vite le gère nativement.

Maintenant, nous sommes prêts à commencer à styliser notre blog !

Développement de la Page de Blog

Nous avons besoin d'une page pour afficher tous nos articles de blog. Comme discuté dans des articles précédents, VitePress traite les fichiers Markdown dans le répertoire src comme des pages. Ainsi, nous allons créer un fichier blog.md dans le répertoire src. Cette page sera liée à la route /blog.

md
---
layout: blog
title: Blog
description: Les derniers articles, tutoriels et ressources sur le développement web, la programmation, et plus encore.
---

Le corps reste vide pour permettre au composant de gérer la structure de la page. Ce composant comprendra :

  • Une liste complète d'articles
  • Un bouton de navigation pour revenir à la page d'accueil

Tip

Déterminez le placement du contenu en considérant le contenu neutre du thème. Par exemple, la liste des articles fait-elle partie du thème ou du contenu ? Un thème peut afficher cette liste sous différents formats — colonne, grille, ou carrousel — ce que le thème dicte. Le contenu doit rester agnostique au thème. Il existe quelques exceptions à cette règle, en particulier pour le contenu intégré.

Routage de la Page de Blog vers le Composant

Dans .vitepress/theme/pages, créons le composant Blog/BlogIndex.vue :

vue
<script lang="ts" setup>

</script>

<template>
  <section>
    <h1>Blog</h1>
  </section>
</template>

Ce composant structure la page. Il utilise le fichier Markdown correspondant pour présenter le titre et les articles.

Dans Layout.vue, lions le layout au composant en utilisant la clé layout du frontmatter du fichier actuel pour afficher le composant adapté.

vue
<script lang="ts" setup>
const { frontmatter } = useData()
</script>

<template>
  <div>
    <main>
      <BlogIndex v-if="frontmatter.layout === 'blog'" />
    </main>
  </div>
</template>

Maintenant, en naviguant vers la route /blog, le composant BlogIndex s'affiche puisque VitePress charge le fichier blog.md, exposant son frontmatter à Layout.vue via la fonction useData.

Chargement de Tous les Articles

Voici maintenant la partie excitante ! Nous allons charger tous les articles du répertoire src/blog. En utilisant les chargeurs de données de VitePress, nous allons le faire avec peu de code et sans surcoût au runtime. ✨

Note

Assurez-vous de la présence de quelques fichiers Markdown dans le répertoire src/blog. Vous pouvez les copier depuis le dépôt GitHub.

Dans un répertoire data au sein de .vitepress, créons le fichier blog.data.ts :

ts
import type { ContentData } from 'vitepress'
import { createContentLoader } from 'vitepress'

declare const data: ContentData[]
export { data }

export default createContentLoader('blog/*.md')

Note

Assurez-vous d'utiliser l'extension .data.ts ; c'est crucial pour le bon fonctionnement.

Que se passe-t-il ici ? VitePress anticipe le chargement de fichiers Markdown locaux, fournissant une fonction utilitaire pour le faire très simplement. Il suffit de spécifier le répertoire et c'est tout !

Le type par défaut peut être incorrect en raison de la transformation côté serveur avant l'accès aux données. Nous devons exporter un type personnalisé via la variable data.

Chargeons ce module dans le composant BlogIndex.vue et rendons-le pour voir le résultat :

vue
<script lang="ts" setup>
import { data } from '../../../data/blog.data'
</script>

<template>
  <section>
    <h1>Blog</h1>

    {{ data }}
  </section>
</template>

La sortie des données est un tableau d'objets, chacun représentant un fichier Markdown. Nous pouvons voir le frontmatter de chaque fichier et son URL :

json
[
  {
    "frontmatter": {
      "title": "Introduction à Vue 3 et Vite",
      "description": "Apprenez à configurer un nouveau projet Vue 3 avec Vite, l'outil de construction rapide pour le développement web moderne. Explorez les bases de Vue 3, y compris l'API de Composition, la réactivité, les composants, et plus encore.",
      "date": "2024-09-14T00:00:00.000Z"
    },
    "url": "/blog/getting-started-with-vue3-and-vite.html"
  },
  {
    "frontmatter": {
      "title": "Introduction à Laravel",
      "description": "Apprenez à configurer un nouveau projet Laravel et à construire une simple application web. Explorez les bases de Laravel, y compris le routage, les vues, les contrôleurs, et plus encore.",
      "date": "2024-10-14T00:00:00.000Z"
    },
    "url": "/blog/getting-started-with-laravel.html"
  }
]

Comment cela fonctionne-t-il ? VitePress utilise un plugin Vite pour détecter les importations d'un fichier .data.ts. Dès détection, le chargement des données se produit, ne retournant que les résultats au client. Par conséquent, les données sont transformées au build-time, offrant une disponibilité immédiate dans le navigateur, semblable aux modules virtuels dans Vite, mais plus adapté aux besoins de VitePress.

Tri des Articles

Actuellement, les articles apparaissent triés par nom, imitant l'ordre du répertoire de fichiers. Nous allons plutôt utiliser la date, mettant en avant les derniers articles en premier.

L'optimisation est réalisable au build-time, évitant de calculer cela à l'exécution lors de l'hydratation.

Dans blog.data.ts, trions les données par date avec un transformateur personnalisé :

ts
import type { ContentData } from 'vitepress'
import { createContentLoader } from 'vitepress'

declare const data: ContentData[]
export { data }

export default createContentLoader('blog/*.md', {
  transform: (data) => {
    return data.sort((a, b) => {
      return (
        new Date(b.frontmatter.date).getTime()
          - new Date(a.frontmatter.date).getTime()
      )
    })
  },
})

Les données apparaissent maintenant triées par date, l'article le plus récent étant en tête.

Note

VitePress met en cache la sortie des données. Pour voir les mises à jour, redémarrez le serveur de développement.

Affichage des Articles

Avec les articles prêts à être chargés et triés, nous n'avons plus qu'à styliser notre blog ! 🎨

Commençons par créer un composant BlogCard.vue dans .vitepress/theme/components :

vue
<script lang="ts" setup>
import { ContentData } from 'vitepress'

defineProps<{
  post: ContentData
}>()
</script>

<template>
  <article
    class="group relative border-4 border-black bg-white p-12 shadow-[8px_8px_0_black] transition duration-150 ease-linear space-y-6 hover:shadow-[12px_12px_0_black] hover:-translate-x-1 hover:-translate-y-1"
  >
    <h2 class="text-4xl text-black font-medium">
      <a :href="post.url">
        {{ post.frontmatter.title }}
        <span class="absolute inset-0" />
      </a>
    </h2>

    <p class="text-xl text-black">
      {{ post.frontmatter.description }}
    </p>
  </article>
</template>

Améliorons le composant BlogIndex.vue pour afficher les articles avec une boucle :

vue
<script lang="ts" setup>
import { data } from '../../../data/blog.data'

const { frontmatter } = useData()
</script>

<template>
  <section class="space-y-16">
    <h1 class="text-6xl font-semibold">
      {{ frontmatter.title }}
    </h1>

    <div class="space-y-10">
      <BlogCard v-for="post in data" :key="post.url" :post="post" />
    </div>

    <div class="flex justify-center">
      <a
        href="/"
        class="border-4 border-black bg-[#FFEB00] px-8 py-4 shadow-[4px_4px_0_black] transition duration-150 ease-linear hover:bg-[#fff90d] hover:shadow-[6px_6px_0_black] hover:-translate-x-[0.125rem] hover:-translate-y-[0.125rem]"
      >Retour à l'accueil</a>
    </div>
  </section>
</template>

Enfin, mettez à jour Layout.vue avec des styles pour améliorer l'attrait visuel du blog :

vue
<script lang="ts" setup>
const { frontmatter } = useData()
</script>

<template>
  <div class="min-h-screen bg-[#FC88FF] pt-16">
    <main class="mx-auto max-w-screen-md">
      <BlogIndex v-if="frontmatter.layout === 'blog'" />
    </main>
  </div>
</template>

Conclusion

Articles de Blog
Articles de Blog

VitePress simplifie la création de pages d'index ! Le chargeur de données permet le chargement et le tri des articles avec un code minimal. Cette fonctionnalité puissante nous permet de nous concentrer sur le développement de contenu et la conception de notre blog.