Плагин для подсветки кода

Markdown-it поддерживает систему плагинов, позволяющую расширять функциональность рендерера. Для подсветки кода чаще всего используют плагин markdown-it-highlightjs, который интегрируется с библиотекой highlight.js. Установка выполняется через npm:

npm install markdown-it markdown-it-highlightjs highlight.js

Импорт и базовая настройка:

const MarkdownIt = require('markdown-it');
const hljs = require('highlight.js');
const markdownItHighlightjs = require('markdown-it-highlightjs');

const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true
});

md.use(markdownItHighlightjs);

После подключения, при рендеринге Markdown-кода все блоки с указанием языка автоматически подсвечиваются:

const source = `
\`\`\`javascript
function hello() {
  console.log("Hello, world!");
}
\`\`\`
`;

console.log(md.render(source));

Результат будет содержать HTML с классами hljs и конкретным языком (language-javascript), что позволяет CSS-стилям highlight.js применяться корректно.


Настройка подсветки через callback-функцию

Markdown-it позволяет настраивать подсветку кода вручную через параметр highlight при инициализации:

const md = new MarkdownIt({
  highlight: function (str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="hljs"><code>` +
               hljs.highlight(str, { language: lang }).value +
               `</code></pre>`;
      } catch (__) {}
    }
    return `<pre class="hljs"><code>` + md.utils.escapeHtml(str) + `</code></pre>`;
  }
});

Особенности такого подхода:

  • Позволяет интегрировать кастомные темы подсветки.
  • Можно добавлять свои CSS-классы для блоков кода.
  • Возможна обработка языков, которые не поддерживаются из коробки, через собственные маппинги.

Поддержка инлайнового кода

Markdown-it автоматически выделяет инлайновый код с использованием тега <code>. Подсветка с highlight.js применяется только к многострочным блокам кода, но можно расширить функциональность, если требуется подсветка инлайнового кода. Для этого создается пользовательский плагин:

function inlineCodeHighlight(md) {
  const defaultRender = md.renderer.rules.code_inline || function(tokens, idx, options, env, self) {
    return self.renderToken(tokens, idx, options);
  };

  md.renderer.rules.code_inline = function(tokens, idx, options, env, self) {
    const content = tokens[idx].content;
    return `<code class="hljs-inline">${md.utils.escapeHtml(content)}</code>`;
  };
}

md.use(inlineCodeHighlight);

Классы hljs-inline можно стилизовать отдельно через CSS.


Расширение подсветки через пользовательские языки

highlight.js позволяет добавлять свои языки или модифицировать существующие. Например, можно зарегистрировать кастомный язык myLang:

hljs.registerLanguage('myLang', function(hljs) {
  return {
    keywords: 'if else for while return function',
    contains: [
      hljs.C_NUMBER_MODE,
      hljs.C_LINE_COMMENT_MODE,
      hljs.C_BLOCK_COMMENT_MODE,
      {
        className: 'string',
        begin: /"/, end: /"/
      }
    ]
  };
});

После регистрации блоки с \```myLang будут подсвечиваться согласно определенным правилам.


Настройка темы подсветки

highlight.js поставляется с набором CSS-тем, которые можно подключить отдельно. Пример подключения темы:

<link rel="stylesheet" href="node_modules/highlight.js/styles/github-dark.css">

Стили применяются автоматически к блокам <pre><code class="hljs">.

Для динамической смены темы можно менять класс на родительском контейнере и подгружать соответствующий CSS, что особенно полезно при реализации светлой и тёмной темы на сайте.


Кеширование рендеринга блоков кода

При рендеринге больших документов стоит учитывать производительность. highlight.js может быть дорогим для множества блоков кода. Для оптимизации можно кешировать результат подсветки:

const codeCache = new Map();

function highlightCached(str, lang) {
  const key = lang + ':' + str;
  if (codeCache.has(key)) return codeCache.get(key);

  const result = lang && hljs.getLanguage(lang)
    ? hljs.highlight(str, { language: lang }).value
    : md.utils.escapeHtml(str);

  codeCache.set(key, result);
  return result;
}

const mdOptimized = new MarkdownIt({
  highlight: highlightCached
});

Это снижает нагрузку при повторных рендерах одинаковых фрагментов кода.


Интеграция с другими плагинами Markdown-it

Markdown-it поддерживает цепочку плагинов. Подсветка кода хорошо сочетается с:

  • markdown-it-anchor – генерация якорей для заголовков;
  • markdown-it-table-of-contents – автоматическая таблица содержания;
  • markdown-it-footnote – сноски и ссылки.

Правильное подключение плагинов в нужной последовательности обеспечивает корректное отображение и подсветку всех элементов документа:

md.use(markdownItHighlightjs)
  .use(require('markdown-it-anchor'))
  .use(require('markdown-it-table-of-contents'));

Обработка ошибок и fallback

Если язык не поддерживается, важно не ломать рендер. Для этого используется fallback:

md.set({
  highlight: function(str, lang) {
    try {
      if (lang && hljs.getLanguage(lang)) {
        return hljs.highlight(str, { language: lang }).value;
      }
    } catch (err) {
      console.error(err);
    }
    return md.utils.escapeHtml(str);
  }
});

Такой подход предотвращает падение рендеринга при неизвестных языках и позволяет безопасно отображать исходный текст кода.