Quand vos blocs de code deviennent muets

Ajouter un langage que Shiki ne connaît pas

15.04.2026 | 27 Shawwal 1447
5 min read

بِسْمِ ٱللَّهِ ٱلرَّحْمَـٰنِ ٱلرَّحِيمِ

Le problème qu’on ne remarque pas

Ce site compte deux articles à propos de Caddy. Tous deux utilisent des blocs de code délimités par ```caddy pour montrer la configuration du Caddyfile. Expressive Code les rend, Shiki les tokenise, la page se construit sans erreurs.

Sauf que chaque bloc Caddy s’affichait comme du texte brut. Pas de coloration syntaxique, pas de couleur, pas de structure visuelle. Juste des caractères monochromes sur un fond sombre.

Les blocs avaient l’apparence du code. Ils avaient les numéros de ligne, le cadre, le bouton de copie. Tout ce qu’ajoute Expressive Code était là. Ce qui manquait, c’était ce qu’ajoute Shiki : la coloration elle-même. Directives, chaînes, commentaires, valeurs, tout dans la même couleur.

Le contraste s’est imposé en comparant le blog à VS Code. La même config Caddy, en couleurs dans l’éditeur, monochrome sur la page.

Pourquoi ça arrive

Expressive Code utilise Shiki pour la coloration syntaxique, et Shiki embarque des grammaires pour plus de 250 langages. JavaScript, Python, TypeScript, Bash, HTML, CSS, Go, Rust. Les langages dont parlent la plupart des blogs techniques.

Lien Externe github.com/shikijs/textmate-grammars-themes/tree/main/packages/tm-grammars

Caddy n’en fait pas partie. Traefik, HAProxy ou Docker Compose non plus, des outils qu’on croise pourtant dans l’infrastructure self-hostée. Quand Shiki rencontre un identifiant de langage qu’il ne reconnaît pas, il retombe sur le texte brut. Aucune erreur, aucun échec de build. Juste un avertissement enfoui dans la sortie de build que personne ne lit vraiment :

[astro-expressive-code] Error while highlighting code block using language "caddy".
The language could not be found. Using "txt" instead.

Le mot «error» est généreux. Rien ne casse. La page se rend. Le bloc de code ressemble à un bloc de code. Il ne fait simplement pas la seule chose qu’un coloriseur syntaxique est censé faire.

D’où viennent les grammaires

Shiki utilise les grammaires TextMate, le même format que celui de VS Code pour la coloration syntaxique. Chaque extension de langage de VS Code embarque un fichier .tmLanguage.json qui définit la façon dont le langage est tokenisé : ce qui est un mot-clé, ce qui est une chaîne, ce qui est un commentaire.

Si VS Code colore correctement votre langage, la grammaire existe déjà. Elle se trouve dans votre dossier d’extensions.

Pour Caddy, l’extension officielle est caddyserver/vscode-caddyfile, publiée sous le nom matthewpi.caddyfile-support. Sous licence MIT.

Lien Externe github.com/caddyserver/vscode-caddyfile

Le fichier de grammaire se trouve à :

~/.vscode/extensions/matthewpi.caddyfile-support-0.4.0/syntaxes/caddyfile.tmLanguage.json

Le même fichier qui permet à VS Code de colorer les Caddyfile peut faire de même avec Expressive Code. On le copie dans son projet, on pointe la config dessus, terminé.

Cinq lignes de config

Expressive Code accepte les grammaires personnalisées via l’option shiki.langs dans ec.config.mjs :

import { defineEcConfig } from 'astro-expressive-code'
import fs from 'node:fs'
const caddyfile_Grammar = {
...JSON.parse(fs.readFileSync('./src/Scripts/Build/Grammars/caddyfile.tmLanguage.json', 'utf-8')),
name: 'caddy',
}
export default defineEcConfig({
shiki: {
langs: [caddyfile_Grammar],
langAlias: { caddyfile: 'caddy' },
},
})

Charger la grammaire, l’ajouter à langs, éventuellement aliaser des noms alternatifs. Le reste de la config ne change pas.

Build du site. Plus d’avertissements. Les blocs de code s’illuminent.

Pourquoi ça ne marchait toujours pas

Sauf qu’ils ne s’illuminaient pas. Pas du premier coup.

La grammaire se chargeait sans erreurs. Le build passait proprement. Les blocs de code continuaient à s’afficher en texte brut. Aucun avertissement, aucun signe que quelque chose clochait.

Le problème venait du champ name de la grammaire. La grammaire Caddyfile se déclare en name: "Caddyfile", C majuscule, F majuscule. Mais les blocs délimités dans les fichiers MDX utilisent ```caddy, en minuscules. Shiki compare les noms de langage en respectant la casse. "Caddyfile" ne correspond pas à "caddy".

L’option langAlias semblait être la solution. Mapper caddy vers caddyfile. Mais l’alias est résolu avant la vérification des langages chargés, et la grammaire s’est enregistrée sous "Caddyfile", pas sous "caddyfile". L’alias pointait vers un nom qui n’existait pas.

Le correctif : surcharger la propriété name de la grammaire au moment du chargement.

const caddyfile_Grammar = {
...JSON.parse(fs.readFileSync('./path/to/caddyfile.tmLanguage.json', 'utf-8')),
name: 'caddy', // override "Caddyfile" to match ```caddy fences
}

Une ligne. La grammaire s’enregistre désormais sous "caddy", les délimiteurs disent caddy, Shiki trouve une correspondance. Tout fonctionne.

C’est le genre de bug qui ne s’annonce pas. Pas de stack trace, pas de message d’erreur, pas de build raté. La grammaire se charge avec succès. Shiki ne la rattache simplement jamais à vos blocs de code. Il faut savoir que la comparaison de noms dans Shiki est sensible à la casse, et il faut savoir que le nom interne de la grammaire peut ne pas correspondre à l’identifiant utilisé dans votre Markdown. Aucun de ces deux points n’est documenté dans le guide d’installation d’Expressive Code.

Lien Externe expressive-code.com/key-features/syntax-highlighting

Le schéma

Ajouter un langage personnalisé à Expressive Code est un processus en trois étapes :

  1. Trouver la grammaire. Regardez dans votre dossier d’extensions VS Code. Si votre éditeur colore le langage, le .tmLanguage.json existe. Copiez-le dans votre projet pour que le build ne dépende pas de la configuration locale de votre éditeur. Vérifiez la licence. La copie embarquée vous appartient à maintenir : les correctifs upstream n’atteindront votre build que si vous recopiez le fichier.

  2. L’enregistrer. Ajoutez-la à shiki.langs dans la config d’Expressive Code. Utilisez langAlias si vous voulez que plusieurs identifiants pointent vers la même grammaire.

  3. Faire correspondre le nom. Surchargez la propriété name de la grammaire pour qu’elle corresponde à ce que vous utilisez dans vos blocs de code délimités. Ne supposez pas que le nom interne de la grammaire correspond à l’identifiant de votre délimiteur.

Tout le processus, une fois qu’on le connaît, est court. Découvrir qu’il faut le faire, et pourquoi la première tentative échoue en silence, c’est là que se trouve le vrai travail.

À quoi ça ressemble maintenant

Avant :

handle_errors {
rewrite * /404.html
file_server
}

Après :

handle_errors {
rewrite * /404.html
file_server
}

Même contenu. Ce qui change, c’est que l’œil du lecteur peut saisir la structure d’un coup d’œil ou doit lire chaque mot. Pour un article qui essaie d’apprendre à quelqu’un comment configurer Caddy, cette différence est inshallah l’écart entre utile et frustrant.

Les blocs de code sur un blog technique sont un signal de crédibilité discret. Quand ils s’affichent avec une coloration complète, personne ne le remarque. Quand ils ne le font pas, ceux qui le remarquent sont précisément ceux qu’on veut voir lire son travail.

Ingénieur aérospatial

Entrepreneur éthique en public

Vous gérez votre activité

Je m'occupe du côté numérique

Travailler avec moi
  • IA avec honnêteté
  • Infrastructure privée
  • Sites web performants

Parlez-moi de votre situation :

javed@javedab.com En savoir plus