Thomas Citharel

Salut, je suis Thomas Citharel, un être humain avec des compétences de développement web.

Publier un blog statique avec Gridsome

Gridsome est un framework pour générer des sites statiques à l'aide de VueJS et GraphQL.

On parle aussi de frameworkJAMStack, pour Javascript, APIs et Markup. En gros, ce terme décrit simplement d'avoir la possibilité d'ajouter des fonctionnalités dynamiques par dessus votre site statique généré à partir de fichiers sources comme du Markdown, le HTML étant hydraté avec l'application Javascript.

Il n'y a pas de fonctionnalités statiques ici, j'ai juste besoin d'un blog, il n'y aura pas grande différence à l'utilisation si jamais vous avez le Javascript activé ou non dans votre navigateur1.

J'ai choisi Gridsome car il utilise le framework VueJS avec lequel je suis plus familiarisé, mais c'est quasiment le même fonctionnement que GatsbyJS qui utilise ReactJS.

J'avais eu l'occasion d'utiliser Gatsby pour entraide.chatons.org et j'avais trouvé le concept intéressant. Aujourd'hui, cet article que vous lisez est justement affiché dans une page d'un site statique généré par Gridsome.

Comme indiqué sur la page de présentation de Gridsome : vous prenez des sources de données en entrée, vous effectuez des traitements sur les données (sélection, transformation, affichage) et vous déployez les fichiers HTML et assets produits.

Créer un projet Gridsome

On commence par installer le module qui fournit la ligne de commande :

yarn global add @gridsome/cli

J'utilise yarn dans les commandes, mais vous pouvez bien sûr utiliser les équivalents npm si c'est ce que vous préférez.

Puis on crée un nouveau projet :

gridsome create mon-site

Cela récupère le modèle du projet, le met à jour avec le nom du projet, et installe les dépendances.

On peut alors se mettre dans le dossier du projet nouvellement créé puis lance le serveur de développement, par défaut sur le port 8080.

cd mon-site
gridsome develop

Structure du projet

Vous devriez avoir une structure de projet équivalente voire égale à celle ci-dessous :

├── gridsome.config.js
├── gridsome.server.js
├── package.json
├── README.md
├── src
│   ├── components
│   │   └── README.md
│   ├── favicon.png
│   ├── layouts
│   │   ├── Default.vue
│   │   └── README.md
│   ├── main.js
│   ├── pages
│   │   ├── About.vue
│   │   ├── Index.vue
│   │   └── README.md
│   └── templates
│       └── README.md
├── static
│   └── README.md
└── yarn.lock

On voit dans src/pages/ les fichiers About.vue et Index.vue, qui correspondent aux deux routes accessibles via la barre de navigation. Notez donc que le routage de base se fait via les fichiers disponibles dans /pages/. Index.vue correspond à la page d'accueil /, et un fichier MonProjet.vue donnerait une route /mon-projet.

On a également le fichier Default.vue dans /src/layouts/. Les layouts sont utilisés pour envelopper vos pages avec des éléments communs aux pages, typiquement l'en-tête de la page, la barre de navigation, le pied-de-page… Dans nos pages, par exemple About.vue, le contenu est enveloppé par l'élément <Layout> :

<template>
  <Layout>
    <h1>About us</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error doloremque omnis animi, eligendi magni a voluptatum, vitae, consequuntur rerum illum odit fugit assumenda rem dolores inventore iste reprehenderit maxime! Iusto.</p>
  </Layout>
</template>

Ajout et représentation des données

Le squelette de notre site étant exploré, voyons comment y insérer nos données. Gridsome utilise GraphQL, un langage de requêtes. Nous avons par exemple un premier exemple de requête GraphQL dans le fichier layouts/Default.vue, où le nom du site (défini dans le fichier de configuration gridsome.config.js) est récupéré avec la requête suivante :

query {
  metadata {
    siteName
  }
}

La variable siteName est alors disponible via l'expression $static.metadata.siteName dans notre template VueJS.

Pour importer nos propres données, prenons l'exemple basique de billets de blog sous forme de fichiers locaux au format Markdown.

Installons les modules @gridsome/source-filesystem afin de récupérer le contenu des fichiers et @gridsome/transformer-remark afin de transformer notre contenu markdown en HTML et surtout convertir l'éventuel front matter YAML en métadonnées utilisables.

Nous allons ajouter la configuration donnée en exemple dans gridsome.config.js :

module.exports = {
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        typeName: 'BlogPost',
        path: './content/blog/**/*.md',
      }
    }
  ],
  templates: {
    BlogPost: '/blog/:year/:month/:day/:title'
  }
}

Puis créons l'arborescence content/blog/2020 et un fichier hello world.md au bout avec le contenu de base suivant :

---
date: 2020-01-05
title: "Hello World"
---
Il s'agit de mon **premier** contenu !

On redémarre le serveur de développement Gridsome car on a changé la configuration puis on ouvre le bac à sable GraphQL pour effectuer nos premières requêtes et voir le résultat facilement.

Par exemple, pour récupérer la liste de tous nos posts, on écrira :

query {
   allBlogPost {
    edges {
      node {
        title,
        date(format: "DD/MM/YYYY"),
        path
      }
    }
  }
}

Si on édite notre page Index.vue, on peut rajouter cette requête dans un bloc <page-query> et ensuite accéder aux données via $page.allBlogPost, comme par comme dans l'exemple suivant où nous rajoutons une liste des billets au template :

<ul v-for="edge in $page.allBlogPost.edges" :key="edge.node.id">
  <li>{{ edge.node.title }}</li>
</ul>

Ajoutons ensuite un fichier BlogPost.vue dans nos templates/ pour représenter ces entités:

<template>
  <Layout>
    <article>
      <h1>{{ $page.blogPost.title }}</h1>
      <span>{{ $page.blogPost.date }}</span>
      <div v-html="$page.blogPost.content"></div>
    </article>
  </Layout>
</template>

<page-query>
query BlogPost($path: String!) {
   blogPost(path: $path) {
        title,
        date(format: "DD/MM/YYYY"),
        content
        path
  }
}
</page-query>

Comme on l'a vu, les données de la requête GraphQL blogPost sont injectées dans la variable $page accessible dans mon template. Maintenant que l'on a une page dédiée pour afficher chaque billet, ajoutons un lien depuis notre liste sur la page Index.vue, en changeant notre <li> en :

<li>
  <g-link :to="edge.node.path">{{ edge.node.title }}</g-link>
</li>

La balise <g-link> crée lors du rendu des balises <a> tout ce qu'il y a de plus basique, mais permet aussi le préchargement des liens (voir les notes de bas de page). En cliquant dessus, on arrive finalement sur notre page montrant un article en particulier.

Génération et publication

Générons maintenant notre site avec gridsome build, puis servons le contenu du dossier dist, par exemple avec serve : serve dist.

Je vous laisse vérifier que la navigation fonctionne bien et que le HTML produit contient bien notre contenu.

On peut publier le contenu de dist là où on le souhaite, voici un exemple de fichier de configuration pour le publier sur Gitlab Pages :

image: node:14
deploy:
  stage: deploy
  script:
    - yarn install
    - yarn build
    - gzip -kv -6 -r public
  artifacts:
    paths:
      - public

Je m'arrête là pour parler de Gridsome, mais j'ai quand même prévu de parler de comment gérer mes contenus sur ce site avec NetlifyCMS, et comment mettre en place un chroot sur un serveur pour y faire un rsync depuis notre CI afin de déployer notre site.


  1. Une différence est que si le Javascript est activé, Gridsome est censé observer les liens internes actuellement affichés à l'écran (avec IntersectionObserver) pour les précharger afin que les chargements de page soient effectués avant même le clic éventuel sur le lien. Les gains devraient rester minimaux étant donné qu'il n'y a qu'un contenu HTML à récupérer depuis le serveur.