Ban's Blog.

Markdown : Syntax highlighting avec prism

Cover Image for Markdown : Syntax highlighting avec prism
Alban Fresil
Alban Fresil

Dans cet article, nous allons explorer l'utilisation des outils remark, prismjs, et Next.js pour ajouter un syntax highlighting et la numérotation des lignes dans les blocs de code écrits en Markdown

Outils utilisés :

Pré-requis :

Pour suivre ce tutoriel, le plus simple est de partir du repo blog-starter fourni par Next. Les différents fichiers seront déjà en place, il n'y aura plus qu'à faire quelques modifications.

Si vous êtes plus expérimenté, vous pouvez évidemment passer cette étape :)

Première étape : import de la bibliothèque

Nous pourrions utiliser le module prismjs mais cela rend plus compliqué l'implémentation du plugin line-numbers, responsable de la numérotation des lignes dans nos blocs de code. Nous allons donc préférer importer la bibliothèque et les feuilles de styles via un cdn et la bibliothèque remark-prism

Nous allons donc commencer par trouver où se trouve la balise <head> dans notre architecture. Avec Next JS, on la place généralement dans _document.tsx, un fichier spécifique à Next.js qui permet de personnaliser le rendu du document HTML principal de votre application.

Il permet de définir des éléments tels que les balises <head>, le <body> et d'ajouter des scripts. Ce composant est appelé une seule fois lors du render initial de l'application et il est partagé par toutes les pages.

// /pages/_document.tsx
import { Html, Head, Main, NextScript } from "next/document";

export default function Document() {
  return (
    <Html lang="en">
      <Head>
        <link
          rel="stylesheet"
          href="https://unpkg.com/prismjs/themes/prism-tsx.css"
        />
        <link
          rel="stylesheet"
          href="https://unpkg.com/prismjs/themes/prism.css"
        />
        <link
          rel="stylesheet"
          href="https://unpkg.com/prismjs/themes/prism-jsx.css"
        />
        <link
          rel="stylesheet"
          href="https://unpkg.com/prismjs/themes/prism-typescript.css"
        />
        <link
          rel="stylesheet"
          href="https://unpkg.com/prismjs/themes/prism-okaidia.css"
        />
        <link
          rel="stylesheet"
          href="https://unpkg.com/prismjs/plugins/line-numbers/prism-line-numbers.css"
        />
        <script src="https://unpkg.com/prismjs/prism.js"></script>
        <script src="https://unpkg.com/prismjs/plugins/line-numbers/prism-line-numbers.min.js"></script>
        <script src="https://unpkg.com/prismjs/components/prism-tsx.js"></script>
        <script src="https://unpkg.com/prismjs/components/prism-typescript.js"></script>
        <script src="https://unpkg.com/prismjs/components/prism-jsx.js"></script>
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

Nous avons simplement ajouté 6 feuilles de style :

  • prism,
  • prism-okaida : un des nombreux thèmes disponibles, les autres thèmes ici
  • prism-line-numbers : le style du plugin affichant les lignes, les autres plugins ici
  • une feuille de style par language hors JS (jsx, tsx, typescript)

Nous avons aussi ajouté 5 balises scripts :

  • prism : le script général de la bibliothèque
  • prism-line-numbers : le script du plugin affichant les lignes
  • un script par language hors JS (jsx, tsx, typescript)

💡 Note :
Avec ces imports, seul javascript sera highlighté. Pour chaque langage, il faudra importer le script et la feuille de style.
Liste des languages

Deuxième étape : modification du module de conversion Markdown vers HTML

Nous devons maintenant modifier le fichier responsable de la conversion Markdown > HTML Dans le repo fourni par next, il s'agit de markdownToHtml.ts.

// lib/markdownToHtml.ts

import { remark } from "remark";
import html from "remark-html";
import prism from "remark-prism";

export default async function markdownToHtml(markdown: string) {
  const result = await remark()
  .use(html,{ sanitize: false })
  .use(prism, { showLineNumbers: true })
  .process(markdown);
  return result.toString();
}

Ici, nous avons importé prism du module "remark-prism"et ajouté en ligne 10 :

.use(prism, { showLineNumbers: true })

Conclusion et sources

Malgré peu de changements dans le code, trouver la bonne solution pour ce cas précis a été surprenamment long. La bibliothèque est un peu capricieuse et je suis content de ne pas avoir eu besoin d'utiliser de tweaks comme c'est le cas dans cet article (Merci à Alan W Smith !) Sur certains devices et certains navigateurs, le plugin line-numbers ne fonctionne pas du tout, mais ne casse pas le syntax-highlighting.