Prendre le socle SEO dans le bundle Nuxt SEO
La couche installe @nuxtjs/seo et lui confie les balises de head et les données structurées qu'elle écrivait à la main, ne gardant que les règles qui dépendent des versions et des traductions.
Contexte
La couche embarquait déjà trois des modules de Nuxt SEO — robots, sitemap et
image OG —, choisis un à un au fil des besoins. Tout ce qu'ils ne couvrent pas
était écrit à la main : un lien canonique, un bloc og:/twitter: par page et un
@graph JSON-LD assemblé dans une chaîne de gabarit au sein de [...slug].vue.
Cela fonctionnait et restait invisible. C'est précisément le problème : rien de
tout cela n'était couvert par un test, parce que le SEO vit dans le HTML rendu et
non dans la logique, et que les tests de ce dépôt ne couvrent délibérément que la
logique pure. La page d'accueil — celle qu'on partage le plus volontiers —
n'avait aucune carte sociale, la page d'erreur était indexable, et sept langues
étaient publiées sans un seul og:locale. Chacune de ces lacunes était un oubli
que personne ne pouvait voir.
La moitié écrite à la main était aussi celle qui grossit. Les données structurées forment une spécification à large surface, dotée de ses propres validateurs ; chaque nœud ajouté à la main est un nœud dont il faut deviner la forme en lisant la spécification.
Décision
La couche dépend de @nuxtjs/seo et le charge comme un seul module, à la place
qu'occupaient les trois modules nommés — avant @nuxt/content, parce que
l'intégration de la sitemap avec Content l'exige.
Le bundle est un alias, pas une surcouche : sa propre documentation indique qu'il
« ne contient aucune logique propre ». Ce qu'il apporte, ce sont les quatre
modules manquants — nuxt-schema-org pour le graphe, nuxt-seo-utils pour le
canonique automatique et les balises sociales dérivées, nuxt-link-checker, et
nuxt-site-config comme unique endroit d'où site.url est lu — ainsi que le
panneau devtools partagé, qui rend compte de ceux qui sont installés.
Trois valeurs par défaut de nuxt-seo-utils sont désactivées, chacune pour une
raison que la couche ne peut pas contourner par conception :
canonicalLowercase, parce qu'un préfixe de langue est sensible à la casse et que
/de-DE/ n'est pas /de-de/ ; fallbackTitle, parce qu'un titre inventé à
partir d'un slug masquerait le validateur de build qui échoue sur une page sans
titre ; et mergeWithSiteConfig, parce que app.vue est propriétaire du gabarit
de titre.
Reste écrit à la main ce que les modules ne peuvent pas savoir : le canonique
d'une page versionnée pointe vers la version courante et non vers la page en
cours de rendu, et noindex découle du fait qu'une version est ancienne ou qu'une
page est servie dans une langue vers laquelle elle n'a pas été traduite.
La vérification des liens signale au lieu d'échouer. modules/validate.ts fait
déjà échouer un build sur un lien qui ne mène nulle part, et c'est la
vérification qui comprend les versions et les replis de langue.
Conséquences
Chaque consommateur de la couche installe sept modules là où il en installait trois. C'est le prix de la décision, et il est payé aussi par les sites qui n'utiliseront aucun des quatre nouveaux.
Les règles qui n'étaient que des affirmations dans un commentaire sont désormais
des assertions dans scripts/check-seo.ts, qui lit les pages construites et
échoue sur un second canonique, un hreflang absent, une page d'erreur
indexable, ou un graphe qui ne s'analyse pas. Il tourne dans check à côté de
check:a11y, pour la même raison : ces balises n'existent que dans le HTML rendu.
Deux de ces règles n'étaient pas vérifiables auparavant, car elles n'existent que
lorsque le site connaît sa propre origine, et www ne déclare volontairement
aucun domaine. La vérification remet donc au serveur construit sa propre adresse,
via les variables d'environnement que les modules lisent déjà, plutôt qu'un
domaine figé dans une configuration qu'un consommateur recopierait.
Publier une Organization exige un fait que la couche ne doit pas inventer :
elle attend donc une nouvelle clé duxt.organization et reste absente tant qu'un
consommateur ne l'a pas renseignée — la même position que l'ADR-0005.
Alternatives envisagées
Garder les trois modules et n'ajouter que nuxt-schema-org. Le changement le
plus étroit, écarté à cause du canonique : la règle de version et le canonique
automatique doivent de toute façon être conciliés, et le faire sans
nuxt-seo-utils revient à conserver le bloc og:/twitter: écrit à la main,
déjà oublié sur deux pages.
Écrire les données structurées à la main et les garder. Cela fonctionnait, sans dépendance, et a été écarté parce que le graphe était déjà la partie la plus susceptible d'être fausse et la moins susceptible d'être remarquée — et parce qu'une deuxième page réclamant un deuxième nœud aurait signifié une deuxième copie de l'identité du site enfouie dedans.
Laisser le vérificateur de liens casser le build. Écarté parce que deux gardiens sur une même règle laissent le plus laxiste décider du moment où un build casse. La vérification qui comprend les versions et les replis de langue de cette couche est la sienne.