Visibilité du site : métadonnées SEO et plan du site

- Read in english
Ressources: garabit

Pour un site web axé sur le contenu, l'optimisation pour les moteurs de recherche (SEO) est essentielle. Elle permet aux utilisateurs de trouver et d'accéder à votre contenu via des moteurs de recherche tels que Google ou Bing, ce qui est l'objectif de ce blog. Si ce n'est pas votre objectif, n'hésitez pas à sauter cet article.

Note

L'optimisation pour les moteurs de recherche (SEO) améliore la qualité et la quantité du trafic sur un site web provenant des moteurs de recherche. Elle se concentre sur le trafic organique plutôt que sur le trafic direct ou payé.

Les Fondamentaux

Commençons par intégrer des métadonnées de base dans notre site web.

Dans un premier temps, nous devons spécifier la langue de notre site web en ajoutant la clé lang dans le fichier config.mts :

ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  lang: 'fr-FR',
})

Ensuite, nous établissons le titre et la description de notre site web en insérant les clés title et description dans le fichier config.mts :

ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...
  title: 'Garabit',
  description: 'Un lieu qui reflète mes pensées et mes idées',
})

Le titre servira également de suffixe pour le titre de chaque page. Par exemple, le titre de la page de blog sera Blog | Garabit.

Nous pouvons vérifier ces ajouts en examinant le code HTML généré dans le répertoire .vitepress/dist.

html
<!DOCTYPE html>
<html lang="fr-FR" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Blog | Garabit</title>
    <meta name="description" content="Les derniers articles, tutoriels et ressources sur le développement web, la programmation et plus encore.">
    <meta name="generator" content="VitePress v1.4.1">
    <!-- ... -->
  </head>
</html>

Note

VitePress intègre ses propres métadonnées dans le code HTML généré, ce qui entraîne plus de balises meta que celles que nous avons ajoutées manuellement.

Métadonnées Statistiques

Ajoutons maintenant quelques métadonnées statiques pour améliorer les capacités SEO. Ces métadonnées s'appliquent uniformément à toutes les pages du site web.

Pour ajouter des métadonnées statiques, insérons la clé head dans le fichier config.mts :

ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...
  head: [
    ['meta', { name: 'twitter:site', content: '@soubiran_' }], // Veuillez changer cela avant de déployer
    ['meta', { name: 'twitter:card', content: 'summary_large_image' }],
    ['meta', { property: 'og:image:width', content: '1200' }],
    ['meta', { property: 'og:image:height', content: '630' }],
    ['meta', { property: 'og:image:type', content: 'image/png' }],
    ['meta', { property: 'og:site_name', content: 'Garabit' }],
    ['meta', { property: 'og:type', content: 'website' }],
    [
      'meta',
      { property: 'og:url', content: 'https://garabit.barbapapazes.dev' }, // Veuillez changer cela avant de déployer
    ],
  ],
})

Ces métadonnées sont utilisées par des réseaux sociaux comme Twitter et Facebook pour afficher un aperçu du site web lorsqu'il est partagé. Le préfixe og indique Open Graph, un protocole qui permet aux pages web de devenir des objets riches dans un réseau social.

Note

Les futurs articles exploreront la génération automatique d'images Open Graph pour les articles de blog.

Métadonnées Dynamiques

Pour un SEO optimal, chaque page devrait comporter un titre Open Graph, une description et une URL canonique. Ce sont des métadonnées dynamiques et varient selon chaque page.

Nous avons deux méthodes pour ajouter des métadonnées dynamiques à notre site :

  • Dans le frontmatter de chaque fichier Markdown : Bien que simple, cette méthode n'est pas la plus maintenable. L'ajout de nouvelles métadonnées nécessite de mettre à jour chaque fichier Markdown et d'écrire du YAML avec des tableaux imbriqués, ce qui peut être fastidieux.
md
---
title: Mon Article de Blog Génial
description: Un article de blog qui changera votre vie
head:
  - - meta
    - property: og:title
      content: Mon Article de Blog Génial
  - - meta
    - property: og:description
      content: Un article de blog qui changera votre vie
---

En raison de la redondance et de la complexité, je souhaite éviter cette méthode.

Heureusement, une seconde méthode existe :

  • Dans le fichier config.mts : Une solution plus maintenable consiste à utiliser l'option transformPageData pour insérer des métadonnées dynamiques dans chaque page, en modifiant les données avant le rendu.
ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...
  transformPageData: (page) => {
    // Initialiser le frontmatter `head` s'il n'existe pas.
    pageData.frontmatter.head ??= []

    // Ajouter les balises meta de base au frontmatter.
    pageData.frontmatter.head.push(
      ['meta', { property: 'og:title', content: pageData.title }],
      ['meta', { name: 'twitter:title', content: pageData.title }],
      ['meta', { property: 'og:description', content: pageData.description }],
      ['meta', { name: 'twitter:description', content: pageData.description }],
    )
  },
})

Cette approche est efficace, permettant l'ajout de multiples métadonnées dynamiques sans modifier chaque fichier Markdown ou dupliquer les métadonnées.

Note

Si vous souhaitez ajouter plus de métadonnées dynamiques, vous pouvez le faire de la même manière que les métadonnées Open Graph en utilisant cette technique.

URL Canonique

L'URL canonique spécifie la version préférée d'une page web, empêchant ainsi les problèmes de contenu dupliqué. Sans cela, les moteurs de recherche peuvent avoir du mal à identifier la même page, quelles que soient les variations d'URL, ce qui peut retarder l'indexation. Cette situation peut se produire plus fréquemment que nous le pensons. Par exemple, un article de blog partagé dans une newsletter pourrait inclure un paramètre de suivi, conduisant le moteur de recherche à indexer l'URL avec le paramètre au lieu de l'URL originale, ou pire, pas du tout. Il est donc crucial d'ajouter une URL canonique à chaque page.

Dans la fonction transformPageData, nous pouvons accéder au path de la page pour inférer l'URL canonique.

Tout d'abord, installons le package ufo, une bibliothèque de manipulation d'URL par UnJS :

bash
pnpm add -D ufo

Ensuite, utilisons ce package pour créer l'URL canonique :

ts
import { joinURL, withoutTrailingSlash } from 'ufo'
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...
  transformPageData: (page) => {
    // Initialiser le frontmatter `head` s'il n'existe pas.
    pageData.frontmatter.head ??= []

    // ...

    // Créer l'URL canonique
    pageData.frontmatter.head.push([
      'link',
      {
        rel: 'canonical',
        href: joinURL(
          'https://garabit.barbapapazes.dev', // Modifiez cela avant le déploiement
          withoutTrailingSlash(pageData.filePath.replace(/(index)?\.md$/, '')),
        ),
      },
    ])
  },
})

La fonction joinURL combine l'URL de base du site avec le chemin de la page, évitant le / pour prévenir les // dans l'URL. La fonction withoutTrailingSlash supprime le slash final du chemin de la page. Si vous préférez un slash final, la fonction withTrailingSlash peut être utilisée alternativement. De plus, index.md ou .md doit être retiré du chemin pour générer une URL propre.

Chaque page dispose désormais d'une URL canonique. Inspectons le code HTML généré pour vérifier l'implémentation.

html
<!DOCTYPE html>
<html lang="fr-FR" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Mon Article de Blog Génial | Garabit</title>
    <meta name="description" content="Un article de blog qui changera votre vie">
    <meta name="twitter:site" content="@soubiran_">
    <meta name="twitter:card" content="summary_large_image">
    <meta property="og:image:width" content="1200">
    <meta property="og:image:height" content="630">
    <meta property="og:image:type" content="image/png">
    <meta property="og:site_name" content="Garabit">
    <meta property="og:type" content="website">
    <meta property="og:url" content="https://garabit.barbapapazes.dev">
    <meta property="og:title" content="Mon Article de Blog Génial">
    <meta name="twitter:title" content="Mon Article de Blog Génial">
    <meta property="og:description" content="Un article de blog qui changera votre vie">
    <meta name="twitter:description" content="Un article de blog qui changera votre vie">
    <link rel="canonical" href="https://garabit.barbapapazes.dev/mon-article-de-blog-genial">
    <!-- ... -->
  </head>
</html>

Concernant les URL propres, vous pourriez remarquer l'extension .html à la fin des URL. VitePress génère des fichiers HTML pour chaque fichier Markdown, facilitant le déploiement puisque le chemin /mon-article-genial.html correspond directement au fichier mon-article-genial.html. Cependant, ce n'est pas très bon pour le SEO ni esthétiquement agréable. En définissant cleanUrls sur true dans le fichier config.mts, nous pouvons éliminer l'extension .html de l'URL :

ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...
  cleanUrls: true,
})

Lorsque ce paramètre est activé, le serveur doit être configuré pour servir l'URL /mon-article-genial avec le fichier mon-article-genial.html, sans redirection. La plupart des services de déploiement comme Cloudflare Pages, Vercel ou Netlify s'y prêtent. Les serveurs personnalisés peuvent nécessiter des ajustements de configuration de proxy inverse.

Warning

Veuillez toujours vous assurer que l'URL canonique correspond à l'URL servie par le serveur. Si vous choisissez de ne pas activer ce paramètre, ajoutez l'extension .html à l'URL canonique.

Plan du Site

Un plan du site aide les moteurs de recherche à indexer un site web. C'est un fichier XML énumérant toutes les URL du site web, permettant aux moteurs de recherche de découvrir efficacement de nouvelles URL sans avoir à explorer entièrement le site.

VitePress simplifie la génération de plans du site. Il suffit d'ajouter trois lignes de code dans le fichier config.mts :

ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...
  sitemap: {
    hostname: 'https://garabit.barbapapazes.dev', // Veuillez changer cela avant de déployer
  },
})

Cela produira un fichier sitemap.xml dans le répertoire .vitepress/dist lors de la construction du site avec pnpm run build. Vous pouvez soumettre ce fichier à la console SEO de votre moteur de recherche préféré.

xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset
  xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
  xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
  xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
  <url>
    <loc>https://garabit.barbapapazes.dev/blog.html</loc>
  </url>
  <url>
    <loc>https://garabit.barbapapazes.dev/blog/getting-started-with-vue3-and-vite.html</loc>
  </url>
  <url>
    <loc>https://garabit.barbapapazes.dev/blog/getting-started-with-laravel.html</loc>
  </url>
  <url>
    <loc>https://garabit.barbapapazes.dev/</loc>
  </url>
</urlset>

Et voilà, le plan du site est prêt à être inclus dans la console SEO de votre choix.

Automatisation de la Mise en Page

Pour conclure cette section, simplifions la mise en page des articles de notre blog. Auparavant, nous devions définir manuellement la clé layout sur blog-show dans le frontmatter de chaque article. Bien que ce ne soit pas difficile, cette étape est oubliable et répétitive à travers les articles, tout comme les métadonnées.

Pour automatiser cela, réutilisons l'option transformPageData pour insérer la clé layout dans le frontmatter de chaque article, en vérifiant si le filePath se trouve dans le répertoire src/blog.

ts
import { defineConfig } from 'vitepress'

export default defineConfig({
  // ...
  transformPageData: (page) => {
    // Définir la mise en page pour les articles de blog
    if (pageData.filePath.startsWith('blog/')) {
      pageData.frontmatter.layout = 'blog-show'
    }
  },
})

Cette approche permet de retirer la clé layout du frontmatter de chaque article, réduisant ainsi les risques d'oubli et minimisant la redondance. Cela illustre la force de l'automatisation !