<!--
  canonical-url: https://www.avonture.be/fr/blog/docusaurus-ascii-art
  published:     2025-11-23
  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.
-->

# Injecter de l'ASCII art dans toutes les pages HTML générées par Docusaurus

> Injectez une bannière en ASCII art dans chaque page HTML générée par Docusaurus grâce à un plugin postBuild léger. Elle apparaît dans le code source de la page ou peut être affichée visiblement.

---
![Injecter de l'ASCII art dans toutes les pages HTML générées par Docusaurus](/img/v2/ascii_art_html.webp)

**TL;DR**

Cet article montre comment injecter une bannière ASCII art personnalisée dans chaque page HTML générée par Docusaurus. Il s'agit de créer un plugin `postBuild` léger qui parcourt les fichiers générés et insère l'ASCII art sous forme de commentaire HTML juste après la balise `<!doctype html>`. Le guide détaille les étapes pour créer le fichier ASCII art, le plugin, et configurer Docusaurus pour l'activer.

C'est peut-être totalement inutile, et seuls les plus curieux le remarqueront, mais nous allons voir comment injecter une bannière ASCII art personnalisée tout en haut de chaque page HTML générée pour notre blog.

Dès maintenant, appuyez sur `CTRL`+`U` (l'équivalent de `View page source`) pour voir ce que nous allons faire dans cet article.

## Le résultat {#the-result}

Une fois le plugin en place (voir plus bas), un `CTRL`+`U` sur n'importe quelle page du site généré affiche ceci, juste après la balise `<!doctype html>` :

![HTML meerkat](./images/html_meerkat.webp)

> **Votre site est manifestement de classe mondiale et absolument unique dans son domaine. ;-):**

## Pourquoi ça fonctionne {#why-it-works}

* Le plugin s'accroche à l'événement `postBuild` de Docusaurus — il ne s'exécute qu'une fois que `yarn docusaurus build` a fini d'écrire le HTML sur le disque.
* Il parcourt chaque fichier `.html` généré dans la sortie du build.
* Pour chacun, il injecte l'ASCII art sous forme de commentaire HTML juste après la balise ouvrante `<!doctype html>` — invisible sur la page affichée, visible uniquement dans le code source.

*Contrairement aux plugins remark que j'ai écrits auparavant (voir [Creating a search\&replace plugin for Docusaurus](/blog/docusaurus-plugin-replace)), celui-ci ne touche pas du tout au Markdown : il travaille sur le HTML généré.*

## Installation {#installation}

### Créez votre logo personnalisé {#create-your-personalized-logo}

D'abord, il nous faut de l'ASCII art. Si vous n'en avez pas encore, vous pouvez utiliser cet outil en ligne : [Image to ASCII Art Converter](https://folge.me/tools/image-to-ascii). Uploadez simplement un petit personnage et convertissez-le. *J'ai aussi abordé la méthode en ligne de commande pour produire ce genre de bannières dans [Bash - ASCII art](/blog/bash-ascii-art).*

Dans votre site Docusaurus, créez le fichier `src/data/banner.txt` et collez-y votre ASCII art. Voici le mien :

**src/data/banner.txt**

```txt


                                                            :+***###%%%%%%%%##****=:
                                                     .-*##%%%%%%##%%%%%%%%%%%%%%%%%%%%##+.
                                                 .=#%%%#%#%+.:..........::--------=#%%%%%%%%*:
                                              .+#%%%##:........:------------------------+%%@@@@@:.
                                          ..=%#%##=......:----------------------------------*%%@@@#..
                                        .:#%##*=.....:----:---------------------------=#@@%+=--*%@@@%-.
                                       :####+.....:-+%@@@*=:-------------------------=@@@@@@@+----#@@@%=.
                                     :#%%#+....:::*@@@@@@@@:-------------------------=**+-+##=------#@@@%-
                                   .*#%%+....:::::=#%*--++-------------------------------------------=#@@@#:
                                  -#%%*....:::::::::------------------------------------=++++++=-----===%@@#-
                                 =#%%=...:::::::--=++++++----------------------------+************+=--===*@@%=
                                +%%%-...:-:::-++************+-----------------------******************====*@@@=.
                               +%%%-..:-----******************+--------------------****#%%%%%%##*******+===*@@@=
                              =%%%-..:----**********%@@@@@@****+------------------***%@@@%**%@@@@@*******===*@@@=
                             -#%%-..:----*******#@@@@%*=-=%@@@%**-----------------*#@#-::....::-#%@@#*****===*@@@%%=.
                         ...=#%%=...:--=******#%@@+-::.....::-%@%*----------------*%-::+@@#-.....:%@@*****+==+#@@@%%%@:
                       .-%%%%%%%=..:---******#@@*-:....+%@@@%-:-%#----------------#==#:..+@@@%-....#@%*****+==*@@@##%%%*.
                     .-%%%%+*%%=..:---*******%@*:.......*@@@@@%--%*---------------==@@#-+%@@@@@-....@@*****+===#@@%#*%%%%.
                    .%%%#=.=%%%=..:--=******#@@*....**==%@@@@@@%:+*----------------*@@@@@@@@@@@-....@%******+==#@@@##+%@%+
                   .%%%#..-#@@@=..:--+******#%@*...:*@@@@@@@@@@%==#-------++++++=--=@@@@@@@@@@@-...=@%******+==+%@@##*%@@%
                   *%%#.:+*%@@#-.:---+*******#@*:...+@@@@@@@@@@%-#=---=*#*+=====*%*=-%@@@@@@@%-...=@%******+====#@@%##%@@%
                   %%%+.++#%@@*-::----********#@#-...-#@@@@@@%=:*+:::=#%#*+++++*#%%%-:=+*#+=-...+%@#******+-:===#@@@#*@@@%
                   %%%+=+##%@@#-------=*********%%*-...:------**-:...=@@%%%%%%@@@@@@#..:=++**#%##********+:..-==#@@@#%@@@:
                   %%%%++**#@@#=------.:**********#%%#####%*#*-:.....+@@@@@@@@@@@@@%-:....:=**********+:.....-==#@@%%%@%:
                   -@@@#+**#@@@+-----:...:*****************-:.........:*@@@@@@@@@@#=-:::....................:-=*%@@@@@%.
                    =@@@%+*#@@@+-----:.......-*+++****=:.................-#@@@@*=--::::=*...................:-=#@@@@+.
                     .%@@@#*%@@%=-----........................:@@#............:-::-:-=%@*:::...............:==*@@@-
                      .-%@@@@@@@*-----.........................:*%@#-:......:::::-=+@@#=::::::............:==+#@@*:
                         .=##%@@@+-----...........................-#%@@@%*===+#@@@%#*::::::::::.........:-==+%@@#:
                              +%@@*-----:.............................:+#******#-:::::::::::::::.......-===*@@@*:
                               =%@@#=-----:...................................::::::::::::::::::....:-====#@@%=.
                                -#@@@*------:................................:::::::::::::::::::::-====+#@@@#:
                                 .-%@@@#-------::......................:::::::::::::::::::::::--=====#%@@@#-        =+*+.
                                   .-%@@@%#==-------::.........::::::::::::::::::::::::::---=====-#%@@@@#:        +%@@%@@*
                                     .:%@@@@%#+========------::::::::::::::::::::------======-*%@@@@@#:.         .#@=--*@%-
                                        .:*@@@@@@%#+--==--------------------------------====#@@@@@+:.            :#@=---@@=
                                           ..:#@@@@@@@@%=------------------------------=-===#@@@:                :#@---=@@=
                                                  .+%@@@=-----------------------------------*%@@:                .#@%*-@@@@@@%+.
                                                    -#@@=------------------------------------#@@+.             .*%%%*%@@=-=%=%@#-
                                                    .*%%-..--------------------:::::::-------#@@@:            -#@=----=@%=*%=+#@*:
                                                     *%%#..----------------:..............:--+%@@:.           +@@+==#%@@*#@#+*%@*:
                                                     +%%%:..-------------:..................:-#@@@%==:    ..-+%%%*+++###%@@@%@@%-
                                                     :#%%:..:----------:......................*@@@@@@%%%%%%%%%%*::=++++++*#@@%+.
                                                  .=#%%%*-...:--------:........................#@@#+++*###*==:..:---===+++*@@#.
                                                -#%%%#=...::---------:.........................=%@@*--::::::::---------==+@@%+
                                             .-#%%%+:..::------------:..........................#@@@=-----------------===@@@*.
                                            :#%%#=...::--------------:..........................-%@@%=-------------====#@@@*.
                                          .#%%%+...:-----------------:..........................:+@@@+==---------====+%%@%:
                                         .%%%*...:::-----------------:...........................-%@@%====--=======+%@@@%
                                        .%%%*..:--------------=%=----:...........................--@@@#++++=====+#@@@@#.
                                        %%%#..::------------+%%+-----:...........................:-%@@%+++++**%@@@@#+.
                                       .%%#:..::----------#@@%*=-----:............................-=@@@@@@@@@@@%#+.
                                       =%%#..-:----------%@@@=+=-----:............................-=#@@@@%#*+=.
                                       :%%%-------------=+%@@#=------:............................-==@@%+
                                        %%%#-------------=+%@@#------:............................:==@@@#
                                        .@@%#=------------=+@@%+-----:.............................==*@@#:
                                         .#@@%*=---------==++@@%-----:.............................===@@@*
                                          .-%@@@%%%%%%%*++++*@@%-----:.............................===%@@*
                                            ..=@@@@@*+++++++@@%=-----:.............................-==+@@#-
                                               =@@#+++++++%@@@+=----:..............................:==+@@@*
                                               =@@#*++%@@@@@%===----:..............................:===%@@*
                                               .=%@@@@@@%%++===-----:..............................:===*@@#:
         .:=+%%@#*++--------:::..........:::-----+%@@#+++++===-----:...............................:===+@@@+
       :+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@#+=====--------:..............................::===+@@@*
      :#%%%******++++++**#######*++++=++++++++*#%%%=.:-------------:............................::::===+%@@*
      -%%%#*********************-:::::::::::::=#%%+..:-------------:..........................::::::===+#@@*.
      .+%%%#*******************=--------------*%%*:.::-------------:........................::::::::====+@@#:
       .=%@@@%#****************=-------------+@@#=..:--------------:......................:::::::::-====+@@#-
         .-#@@@%%*********####*=============+@@@+..:---------------:....................::::::::::-=====+@@@+
           ..+%@@@@@@#***#####+=============#@@*..:-----------------:................::::::::::::-======+@@@+
                .#@@@@@@@@%###+============+@@@*.:-------------------:............::::::::::::::========+@@@+
                    .*%%@@@@@@@@@@%*=++++++#@@*..:---------------------:.......::::::::::::::--=====+===+@@@+
                         .:*##%@@@@@@@@@@@@@@@*.:-------------------------::::::::::::::::--============+@@@+
                                  .:=+***##@@@*.:-----------------------======---------===========+=+===+@@@+
                                          :@@%+:--------------------================================+===+@@@+
                                          :@@%=------------------====================++++++++++++++=====+@@@+
                                         .:@@#=---------------==========*###%@@@@@@@@@@@@%%##*+==+++====+@@%=
                                         .-@@%=------------=========*#%@@@@@@@@##@@@@@@@@@@%##*+++++++++*@@#-
                                          :@@%+----------========+#%@@@#=-...    :@@@%++++++++++++++++++*@@#:
                                       =#%%@@%*-------=========+#@@@*-.          .-@@@#=++++++++++++++++*@@@@%%*:
                                     =%%@@#:::------==========+%@@#:.             .=@@%*+++++++++++++++++=-=*%@@@%-
                                    #@@@....-----============+@@@#                 .*@@#++++++++++++++++++++=--*@@@:
                                  .:%@@@@@@@@@@@@@@@@@@@@@@@@@@@#                   :%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#:
                                  .+############################:                    :##############################:.
```

### Créez le plugin et chargez-le {#create-the-plugin-and-load-it}

Passons au plugin. Créez `plugins/ascii-injector/index.mjs` et copiez/collez le code source ci-dessous dans votre fichier :

**plugins/ascii-injector/index.mjs**

```mjs
/**
 * Docusaurus Plugin: ascii-injector
 *
 * Purpose:
 * This plugin will prepend an ASCII art banner (from a specified text file)
 * in all generated HTML files as an HTML comment.
 *
 * Usage:
 * - Save this plugin as `plugins/ascii-injector/index.mjs`
 * - Create the file containing the ASCII art in `src/data/banner.txt`.
 * - Add the plugin to `docusaurus.config.js` plugins array.
 *
 * Please see readme.md for more details
 */

import { promises as fs } from "node:fs";
import path from "node:path";

/**
 * Recursively collect all HTML files in a given directory.
 */
async function collectHtmlFiles(dir) {
  const entries = await fs.readdir(dir, { withFileTypes: true });
  const files = await Promise.all(
    entries.map(async (entry) => {
      const fullPath = path.resolve(dir, entry.name);
      if (entry.isDirectory()) return collectHtmlFiles(fullPath);
      if (entry.isFile() && entry.name.endsWith(".html")) return [fullPath];
      return [];
    }),
  );
  return files.flat();
}

/**
 * Docusaurus plugin that injects an ASCII art banner into all generated HTML files.
 *
 * @param {object} context - Docusaurus plugin context (unused).
 * @param {object} options - Plugin configuration options.
 * @param {string} options.bannerPath - Relative path (from siteDir) to the ASCII banner file.
 */
export default function asciiInjectorPlugin(context, options) {
  if (!options || typeof options.bannerPath !== "string") {
    throw new Error("[ascii-injector] Missing required option: bannerPath (string)");
  }

  return {
    name: "ascii-injector-plugin",

    async postBuild({ outDir, siteDir }) {
      const bannerPath = path.resolve(siteDir, options.bannerPath);

      let rawBanner;
      try {
        rawBanner = await fs.readFile(bannerPath, "utf8");
      } catch (err) {
        console.error(`[ascii-injector] Banner file missing: ${err.message}`);
        return;
      }

      const commentBanner = `<!--\n${rawBanner}\n-->\n\n`;

      const htmlFiles = await collectHtmlFiles(outDir);
      console.log(
        `[ascii-injector] Preparing to inject banner into ${htmlFiles.length} HTML files...`,
      );

      const results = await Promise.allSettled(
        htmlFiles.map(async (filePath) => {
          try {
            const html = await fs.readFile(filePath, "utf8");

            // proceed to inject; files are always regenerated during build

            let updated;

            // Default: insert comment after <!doctype ...>
            const doctype = /<!doctype[^>]*>/i;
            if (doctype.test(html)) {
              updated = html.replace(doctype, (m) => `${m}\n${commentBanner}`);
            } else {
              // fallback to prepending comment
              updated = commentBanner + html;
            }

            // Write atomically: temp file + rename avoids race conditions
            // with other postBuild plugins that read HTML concurrently.
            const tmpPath = `${filePath}.tmp`;
            await fs.writeFile(tmpPath, updated, "utf8");
            await fs.rename(tmpPath, filePath);
            return { status: "ok", filePath };
          } catch (err) {
            return { status: "error", filePath, error: err };
          }
        }),
      );

      const ok = results.filter(
        (r) => r.status === "fulfilled" && r.value && r.value.status === "ok",
      ).length;
      const skipped = results.filter(
        (r) => r.status === "fulfilled" && r.value && r.value.status === "skipped",
      ).length;
      const failed =
        results.filter(
          (r) => r.status === "fulfilled" && r.value && r.value.status === "error",
        ).length + results.filter((r) => r.status === "rejected").length;

      console.log(
        `[ascii-injector] Injection complete — ok: ${ok}, skipped: ${skipped}, failed: ${failed}`,
      );
    },
  };
}
```

C'est presque fini. Finalisez l'installation en éditant votre fichier `docusaurus.config.js` et, sous `plugins`, faites ceci :

**docusaurus.config.js**

```javascript
// [...]
plugins: [
    // [...]
    [
        "./plugins/ascii-injector/index.mjs",
        { bannerPath: "src/data/banner.txt" },
    ],
],
```

Dernière étape : redémarrez votre site Docusaurus pour charger le fichier de configuration mis à jour.

## Autres démos {#more-demos}

### Place aux tests {#time-to-test}

Rien de neuf ici, générez simplement la version statique de votre site.

```bash
$ yarn docusaurus build
$ yarn docusaurus serve
```

Une fois votre site généré, ouvrez n'importe quelle page, appuyez sur `CTRL`+`U` et tadaaa, votre ASCII art est là — exactement le résultat montré en haut de cet article.

## Sous le capot (passez votre chemin si vous voulez juste l'utiliser) {#under-the-hood-skip-this-if-you-just-want-to-use-it}

> **Pas en mode preview:**
>
> Ce plugin n'est déclenché que lors de l'événement `postBuild`, c'est-à-dire uniquement après que votre blog a été rendu sous forme de page HTML. Donc si vous lancez Docusaurus en mode preview, vous ne verrez pas l'ASCII art.

## Conclusion {#conclusion}

Un plugin `postBuild`, un fichier ASCII art et trois lignes de configuration en plus — et chaque page générée par votre site porte dans son source une petite signature inutile, totalement assumée. Si le côté ligne de commande de la génération de bannières ASCII vous intéresse plus que la tuyauterie Docusaurus, [Bash - ASCII art](/blog/bash-ascii-art) couvre cette partie.
