Les inscriptions sont fermées. Menestrel sert désormais aux sites réalisés par Agora Studio, agence web dans la Loire.

Migrer de Decap CMS vers un CMS hébergé, étape par étape

Decap est gratuit et entretenu a minima. Si vous déplacez un site Astro, voici la séquence réelle, ce qui casse, et comment garder un retour arrière qui fonctionne.

Decap CMS, anciennement Netlify CMS, fait tourner un grand nombre de petits sites et n’est plus entretenu qu’a minima : les versions sont rares, la liste de tickets est longue, et une bonne partie de la communauté est passée à Sveltia ou ailleurs.

Ce n’est pas une raison de partir en soi. Un logiciel qui fonctionne et cesse de bouger n’est pas une crise. Les raisons de partir sont en général plus concrètes : le compte GitHub que votre client n’arrive pas à gérer, les vingt fichiers de configuration que vous tenez à la main, ou la construction qui échoue en silence pendant que tout le monde croit le site à jour.

Si vous avez décidé de déplacer un site Astro, voici la séquence qui fonctionne.

Avant tout : décider ce que vous réparez

Les migrations échouent quand personne n’a écrit le problème. Choisissez dans cette liste, honnêtement :

Si aucun de ces points ne mord, ne migrez pas. Decap est gratuit et fonctionne.

Étape 0 : savoir ce que vous avez

Le modèle de Decap est un config.yml décrivant collections et champs, plus des fichiers markdown avec du frontmatter.

Faites l’inventaire avant de toucher à quoi que ce soit :

# Quelles collections existent, et combien d'entrées dans chacune
ls -1 src/content/*/ | head -50

# Quelles clés de frontmatter sont réellement utilisées
grep -h '^[a-z_]*:' src/content/**/*.md | cut -d: -f1 | sort | uniq -c | sort -rn

# Combien pèsent les médias, et sont-ils dans Git
du -sh public/images/ src/assets/ 2>/dev/null
git count-objects -vH | grep size-pack

Cette troisième commande est souvent le moment où l’on réalise la quantité d’images mortes qui traînent dans l’historique.

Notez tout ce qui sort de l’ordinaire : des widgets Decap sans équivalent propre, des champs list contenant des objets, des widgets de relation pointant d’une collection à l’autre. Ce sont les parties qui demandent des décisions plutôt qu’une traduction mécanique.

Étape 1 : écrire le schéma

Votre config.yml devient un fichier TypeScript. La correspondance est presque directe :

Widget Decap Équivalent
string fields.text()
text fields.textarea()
markdown fields.richtext()
number fields.number()
boolean fields.boolean()
datetime fields.datetime()
date fields.date()
select fields.select()
image fields.image()
file fields.file()
object fields.group()
list (d’objets) fields.repeater()
relation fields.relation()

Deux correspondances demandent une réflexion plutôt qu’une traduction.

Une list de chaînes simples. Decap permet une liste de chaînes nues. Il n’y a pas d’équivalent direct, et la réponse honnête est un répéteur avec un seul champ texte dedans, un peu plus lourd à l’édition et bien plus clair dans les données.

Les champs cachés et calculés. Decap a des widgets hidden portant des valeurs que l’éditeur ne saisit jamais. Ces valeurs ont en général leur place dans vos gabarits plutôt que dans le contenu, et une migration est un bon moment pour les y remettre.

Étape 2 : importer, ne pas ressaisir

C’est l’étape qui sauve la journée, parce que votre contenu est déjà du markdown dans des content collections Astro, exactement ce que l’importeur lit :

npx menestrel import

Il parcourt vos collections, déduit la forme de ce qui est présent, envoie les images et réécrit les références. Sur un site vitrine, il tourne en général en quelques minutes.

Lancez-le d’abord contre un projet neuf, pas celui que vous comptez garder. Regardez ce qui en sort, ajustez le schéma, relancez. Il est reprenable et idempotent : interrompez-le et relancez-le, il repart où il s’était arrêté sans rien dupliquer.

Points à vérifier dans le résultat : les dates qui étaient des chaînes et sont devenues des dates, le markdown qui contenait du HTML brut, les chemins d’images relatifs que le scanner n’a pas su résoudre, et les entrées dont les champs obligatoires se révèlent vides à la source.

Étape 3 : changer le loader

Le côté Astro est le plus petit changement :

import { defineCollection } from 'astro:content';
import { menestrelLoader } from '@menestrel/astro';

export const collections = {
  services: defineCollection({ loader: menestrelLoader({ collection: 'services' }) }),
};

Vos composants de page ne changent pas. getCollection(), render() et le typage se comportent exactement comme avant, parce que le Content Layer a rendu la source branchable. C’est ce qui rend cette migration bon marché.

Les images sont le seul endroit où les gabarits demandent en général une retouche : les chemins deviennent des objets portant dimensions et texte alternatif, ce qui est une amélioration mais pas un changement neutre.

Étape 4 : garder un retour arrière qui marche

Ne supprimez rien. En particulier :

Une migration sans retour arrière testé n’est pas une migration, c’est un saut.

Étape 5 : déplacer le client, pas seulement le contenu

La partie technique est la moitié facile. Le client a des automatismes sur un outil qui va disparaître.

Ce qui marche : accomplir sa vraie tâche devant lui, une fois, puis lui laisser la souris et le regarder faire. Pas une visite de l’interface, une vraie modification sur une vraie page qui l’intéresse.

Ce qu’il faut lui dire explicitement, parce que c’est le seul vrai changement de comportement : publier prend maintenant une ou deux minutes, et l’interface lui dira quand c’est réellement en ligne. Sous Decap, enregistrer paraissait instantané et être en ligne était une inconnue. Désormais, enregistrer est instantané, et publier est visible et prend un moment. C’est mieux, et ça surprend les gens si personne ne le dit d’abord.

Étape 6 : traiter le poids du dépôt

Une fois le contenu déplacé, il vous reste un dépôt portant chaque version de chaque photo que le client a jamais envoyée. Retirer les fichiers de l’arbre de travail ne l’allège pas : Git garde l’historique.

Vous avez trois options, par ordre croissant de perturbation.

Ne rien faire. Parfaitement valable. Quelques centaines de mégaoctets sont gênants sur un clone neuf et sans importance le reste du temps. Si le site est stable et que l’équipe c’est vous, laissez tomber.

Archiver et repartir propre. Posez une étiquette sur l’état courant, gardez l’ancien dépôt comme archive, et initialisez-en un nouveau depuis l’arbre actuel. Vous perdez l’historique consultable dans le dépôt actif et le gardez dans l’archive. C’est en général le choix pragmatique pour un site client, où personne n’a jamais eu besoin de lire un commit de trois ans.

Réécrire l’historique avec git filter-repo pour retirer les images. Ça marche, ça produit un dépôt réellement petit, et ça réécrit chaque empreinte de commit, ce qui casse tous les clones existants et toutes les références à un commit. Cela ne vaut le coup que si le dépôt est partagé et assez gros pour faire mal.

Quel que soit le choix, faites-le après que la migration est confirmée et que la branche de retour arrière n’est plus nécessaire, pas avant.

Un calendrier réaliste

Pour un site vitrine unique avec quelques collections et deux cents images, fait correctement plutôt qu’héroïquement :

Étape Durée
Inventaire et décisions 30 minutes
Écriture du schéma 30 à 60 minutes
Premier import, relecture, ajustement, ré-import 1 heure
Changement de loader et retouche des gabarits d’images 1 heure
Tests, dont une construction complète et une passe visuelle 1 heure
Passation au client 20 minutes

Soit environ une demi-journée, dont l’essentiel est de la relecture plutôt que de la saisie. Le deuxième site prend la moitié, parce que le schéma est un fichier qu’on copie.

Prévoyez davantage si vous utilisiez le circuit éditorial, si vous avez des relations entre collections, ou si votre markdown contient du HTML brut. Ce sont les trois endroits où passent les heures.

Ce qui casse réellement

D’après des migrations sur de vrais sites :

Les dates. Le datetime de Decap stocke des chaînes au format que la configuration a fixé. Les fuseaux horaires sont là où se logent les surprises. Vérifiez quelques entrées à la main.

Le HTML brut dans le markdown. Le texte enrichi est structuré, donc une <div> égarée dans un corps markdown ne survit pas intacte. Cherchez les < dans votre contenu avant de migrer et décidez quoi en faire.

Les relations par chemin de fichier. Les relations Decap s’appuient souvent sur un chemin. Les chemins changent. Tout ce qui est relationnel mérite un coup d’œil manuel après import.

L’état de brouillon. Le circuit éditorial de Decap, si vous l’utilisiez, n’a pas d’équivalent direct. Les entrées arrivent en brouillon ou publiées ; la relecture par branche ne se transpose pas.

Quand ne pas faire ça

Disons-le franchement : si vous êtes le seul éditeur, Decap ne coûte rien et fonctionne, et cette migration vous apporte très peu. Restez.

Si votre client exige réellement que le contenu vive dans son dépôt, nous ne répondons pas du tout à cette exigence, et Sveltia ou Keystatic sont les meilleurs choix.

Et si ce qui vous gêne est le rythme de maintenance de Decap plutôt que ce qu’il fait, passer à Sveltia est un changement bien plus léger que de partir vers un service hébergé.

Le comparatif complet détaille ces arbitrages, y compris ce que les outils gratuits font encore mieux.

Retour au blog