<!--
  canonical-url: https://www.avonture.be/fr/blog/docusaurus-plugin-replace
  published:     2025-09-18
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Créer un plugin de recherche/remplacement pour Docusaurus

> Remplacez automatiquement « markdown » par « Markdown » dans tout votre contenu pour garder des articles cohérents.

---
![Créer un plugin de recherche/remplacement pour Docusaurus](/img/v2/docusaurus_component.webp)

**TL;DR**

Cet article montre comment créer un plugin remark personnalisé pour Docusaurus afin de rechercher et remplacer automatiquement certains termes sur tout votre site. L'objectif : garantir une terminologie cohérente (par exemple transformer « vscode » en « VSCode ») sans modifier les fichiers Markdown d'origine. Vous allez apprendre à écrire un plugin qui parcourt l'arbre syntaxique abstrait (AST) du contenu pour n'appliquer les remplacements qu'au texte brut, en évitant les blocs de code et les URL. Le guide montre aussi comment configurer le plugin dans votre `docusaurus.config.js`.

Pour le fun (parce que cette solution n'est peut-être pas infaillible), j'ai demandé à une IA de générer un plugin capable de scanner mes 200 articles et de remplacer des motifs comme `docusaurus` par `Docusaurus`, `github` par `GitHub`, `vscode` par `VSCode`, afin de normaliser tout mon contenu.

Ça peut être risqué, car si le mot `vscode` apparaît :

* dans une URL (comme `https://github.com/microsoft/vscode/`),
* dans un nom (comme `vstirbu.vscode-mermaid-preview`),
* dans un nom de fichier (comme `vscode.png`),
* dans un snippet de code (à l'intérieur d'un bloc ` ```...``` ` ou `` `.` ``),
* ...

nous ne voulons évidemment pas faire le remplacement.

Mais si le mot se trouve dans un simple paragraphe, c'est une autre histoire : là, oui, on veut le remplacement.

Donc, après quelques prompts avec l'IA, un plugin a été généré et il fonctionne jusqu'ici.

Redémarrez votre serveur Docusaurus une fois le plugin en place et, au démarrage suivant, si des changements doivent être faits, vous les verrez dans votre console :

```bash
🔎 Replacing 'vscode' with 'VSCode' in file: /opt/[...]/index.md
Sentence: One of the best features in vscode is the

🔎 Replacing 'vscode' with 'VSCode' in file: /opt/[...]/index.md
Sentence: With vscode, it's ultra-simple: multiple cursors.
```

Silencieux, sûr, et ça ne touche jamais vos fichiers Markdown d'origine : uniquement le HTML généré. Construisons-le.

## Le plugin {#the-plugin}

Créez le fichier `plugins/remark-replace-terms/index.cjs` et regardez le tableau `replacements`. Ajoutez-y les vôtres.

*Il s'agit d'un plugin **remark** : il parcourt l'AST Markdown avant la production du HTML. J'ai utilisé le même mécanisme pour [remplacer chaque balise `<img>` par mon propre composant](/blog/docusaurus-override-img) et pour [injecter des tooltips générés par IA dans les snippets de code](/blog/docusaurus-eli5-snippet-tooltips).*

La syntaxe est `[/\b(1)\b/g, "(2)"],` où `(1)` est le mot à rechercher (écrit exactement tel quel, sensible à la casse) et `(2)` la valeur de remplacement.

**plugins/remark-replace-terms/index.cjs**

```cjs
/**
 * @fileoverview
 * Docusaurus Remark Plugin – remark-replace-words
 *
 * This plugin is designed for use with Docusaurus to automatically correct the casing
 * of common technology terms in Markdown content. It scans Markdown AST text nodes and
 * replaces lowercase variants like "github" or "markdown" with their properly capitalized
 * forms ("GitHub", "Markdown", etc.).
 *
 * ⚠️ Replacements are skipped inside links, images, and code blocks to avoid unintended changes.
 * 🧠 Compound words (e.g., "vscode-docker") are also preserved.
 *
 * Intended for use in the Docusaurus Markdown pipeline via `remarkPlugins`.
 *
 * @module remarkReplaceWords
 * @returns {Function} A remark transformer function
 */

const { visit } = require("unist-util-visit");

// Define replacements as [searchRegex, replacement]
const replacements = [
  [/\bdocusaurus\b/g, "Docusaurus"],
  [/\bgithub\b/g, "GitHub"],
  [/\bmarkdown\b/g, "Markdown"],
  [/\bvscode\b/g, "VSCode"],
];

// A heading's explicit anchor id — `## Docusaurus {#docusaurus}` — is still ordinary text when
// this plugin runs: it sits in `beforeDefaultRemarkPlugins`, so Docusaurus parses that `{#id}`
// suffix only afterwards. Capitalizing a term inside it rewrites the id itself (`{#Docusaurus}`),
// and every link built from the English slug then points at an anchor the page no longer has —
// which is exactly how the `fr` build died on "broken anchors". Ids are never prose: skip them.
// Translated articles carry one on every heading (see scripts/lib/translate-anchors.mjs).
const EXPLICIT_HEADING_ID = /\{#[^}\s]*\}/g;

/** Applies `transform` to `value`, leaving every explicit `{#heading-id}` untouched. */
function outsideHeadingIds(value, transform) {
  const parts = [];
  let cursor = 0;

  for (const match of value.matchAll(EXPLICIT_HEADING_ID)) {
    parts.push(transform(value.slice(cursor, match.index)), match[0]);
    cursor = match.index + match[0].length;
  }
  parts.push(transform(value.slice(cursor)));

  return parts.join("");
}

function remarkReplaceWords() {
  return (tree) => {
    visit(tree, "text", (node, index, parent) => {
      if (typeof node.value !== "string") return;

      // Skip inside certain node types (URLs, code, etc.)
      const forbiddenParents = ["link", "image", "inlineCode", "code"];
      if (parent && forbiddenParents.includes(parent.type)) {
        return;
      }

      node.value = outsideHeadingIds(node.value, (text) => {
        let result = text;

        for (const [regex, replacement] of replacements) {
          result = result.replace(regex, (match, offset, fullString) => {
            const before = fullString[offset - 1] || "";
            const after = fullString[offset + match.length] || "";

            // Skip compound words like "vscode-docker", "foo.markdown"
            if (["-", ".", "/"].includes(before) || ["-", ".", "/"].includes(after)) {
              return match;
            }

            return replacement;
          });
        }

        return result;
      });
    });
  };
}

module.exports = remarkReplaceWords;
```

## Ajouter le plugin dans votre configuration {#adding-the-plugin-in-your-configuration}

L'étape suivante consiste à enregistrer votre plugin dans la configuration de Docusaurus. Pour ce faire, éditez votre fichier `docusaurus.config.js` et ajoutez les lignes surlignées comme illustré ci-dessous.

**docusaurus.config.js**

```javascript
// highlight-next-line
import remarkReplaceWords from "./plugins/remark-replace-terms";

const config = {
  // [ ... ]
  presets: [
    [
      'classic',
      ({
        // [ ... ]
        blog: {
          beforeDefaultRemarkPlugins: [
            // [ ... ]
            // highlight-next-line
            remarkReplaceWords
          ],
        },
        // [ ... ]
      }),
    ],
  ],
};

export default config;
```

Cela fait, redémarrez votre serveur Docusaurus et vous obtiendrez la même sortie console que celle montrée au début de cet article.

> **Caution:**
>
> La recherche/remplacement ne sera pas effectuée sur vos fichiers Markdown d'origine, mais uniquement lors du rendu HTML. Lancer ce plugin est donc sans danger ; vos fichiers ne seront pas impactés du tout.
