Сборка документации

Статья создана
Обновлена 3 июня 2026 г.

Cборка проекта выполняется командой yfm build с параметрами:

  • --input, -i — путь до директории проекта (по умолчанию — текущая папка);
  • --output, -o — путь до директории для выходных данных (обязательный параметр).
# полная команда
yfm build -i ./input-folder -o ./output-folder

# также, доступна сокращенная форма без build
yfm -o ./output-folder

Стандартным выходным форматом сборщика является HTML.

Полный список параметров сборки можно найти в статье или вывести в консоли командой yfm build --help.

YFM → YFM

Вы можете выполнить промежуточную сборку YFM в YFM. Для этого при выполнении команды укажите ключ запуска --output-format=md.

При сборке в YFM выполняются:

Используйте этот вид сборки, чтобы поддерживать несколько вариантов документации для разных пользователей. Если в документации есть разделы с внутренней информацией, вы можете держать два репозитория — приватный и публичный, и синхронизировать приватный в публичный с помощью условий.

Watch-режим

Beta-функциональность

При возникновении проблем сообщите об этом с помощью GitHub issues.

Вы можете автоматизировать пересборку отдельных статей при их изменении. Для этого вызовите yfm build с параметром --watch: после сборки проекта программа перейдёт в режим инкрементальной пересборки и будет создавать или обновлять статьи после сохранения изменений в исходных файлах документации.

Для удобства, после пересборки открытого в браузере файла выполняется автоматическая перезагрузка страницы.

Статистика сборки

При запуске с ключом --build-stats (или buildStats: true в файле конфигурации) рядом с output записывается файл yfm-build-stats.json с метриками текущей сборки. Файл предназначен для CI-дашбордов, отслеживания регрессий и диагностики — для рантайма он не нужен.

По умолчанию включено для сборок --output-format=md, для остальных форматов — выключено. Чтобы отключить, передайте --no-build-stats или укажите buildStats: false в файле конфигурации.

Что попадает в файл:

  • cli — версия пакета, версия Node, платформа, архитектура, релиз ОС.
  • buildstartedAt, finishedAt, durationMs, грубое разбиение по фазам phasesMs.{prepare, entries, finalize} (на основе времени Entry-хука), outputFormat, langs, inputDir, outputDir, features (включённые булевы флаги), memoryUsageMb (heapUsed в момент завершения, в МБ), worker.maxOldSpace.
  • counterstocs, entriesPlanned / entriesProcessed, разбивки entriesByExtension и entriesByLang, headings и contentBytes (для md-страниц), graph.{entries, sources, resources, missed, edges} — снимок графа зависимостей (страницы, включаемые файлы, ассеты, отсутствующие пути, число рёбер), а также warnings / errors (общее число) и warningsByCode / errorsByCode — разбивка по кодам ошибок (YFM013, YFM016 и т.п.; сообщения без распознанного кода попадают в бакет (uncoded)).
  • outputfiles, totalBytes, bytesByExtension.
  • schemaVersion — версия формата файла. При расширении формата схема будет совместимой; ломающие изменения увеличат это число.

Пример выходного файла:

{
  "schemaVersion": 1,
  "cli": { "version": "5.29.0", "node": "v22.22.0", "platform": "darwin", "arch": "arm64" },
  "build": {
    "durationMs": 1474,
    "phasesMs": { "prepare": 1242, "entries": 148, "finalize": 84 },
    "outputFormat": "html",
    "langs": ["ru", "en"],
    "features": ["addAlternateMeta", "allowHtml", "buildStats", "sanitizeHtml"],
    "memoryUsageMb": 256
  },
  "counters": {
    "tocs": 3,
    "entriesPlanned": 133,
    "entriesProcessed": 133,
    "entriesByExtension": { ".md": 122, ".yaml": 11 },
    "entriesByLang": { "ru": 91, "en": 42 },
    "headings": 345,
    "contentBytes": 1693771,
    "graph": { "entries": 130, "sources": 12, "resources": 74, "missed": 0, "edges": 129 },
    "warnings": 3,
    "errors": 1,
    "warningsByCode": { "YFM013": 2, "(uncoded)": 1 },
    "errorsByCode": { "YFM016": 1 }
  },
  "output": {
    "files": 421,
    "totalBytes": 45350699,
    "bytesByExtension": { ".html": 2865454, ".js": 9721257, ".png": 24588860 }
  }
}

Карта содержимого сборки

При запуске с ключом --build-content (или buildContent: true в файле конфигурации) рядом с output записывается файл yfm-build-content.json с отпечатком содержимого каждой страницы и ассета. Файл предназначен для внешних инструментов, которые сравнивают две сборки и точно определяют список изменившихся страниц — переиндексация поиска, уведомления об изменениях и т.п. Для рантайма он не нужен.

По умолчанию включено для сборок --output-format=md, для остальных форматов — выключено. Чтобы отключить, передайте --no-build-content или укажите buildContent: false в файле конфигурации.

Сама сборка не знает ни о каких других ревизиях и не выполняет инкрементальную сборку: diff вычисляется как пост-обработка двух файлов манифеста.

Что попадает в файл:

  • schemaVersion — версия формата файла. При расширении формата схема будет совместимой; ломающие изменения увеличат это число.
  • contentHashes — таблица, ключи которой — исходные пути (стабильны между сборками; output-пути могут меняться из-за hashIncludes). Для каждого файла: hash (sha256 от стабильного представления файла в output, с префиксом sha256-) и size (размер файла в output в байтах). Стабильное представление — это файл с вырезанными перед хешированием полями VCS (updatedAt, contributors, author) и CLI-полем metadata.generator из frontmatter .md и блока meta: в .yaml. Так хеш отражает то, что видят читатели, а не каждый коммит или релиз CLI. Бинарные ассеты хешируются как есть.
  • pageAssets — для каждой страницы — отсортированный список её прямых зависимостей типа resource (картинки, видео, SVG и т.п.), приведённых к исходным путям. Нужен потому, что ссылки на ассеты не имеют фингерпринта в теле страницы: изменение pic.png не меняет хеш страницы, но меняет contentHashes["pic.png"], и pageAssets позволяет потребителю связать одно с другим.

Как изменения во вставках попадают в diff:

  • mergeIncludes: true — содержимое вставки встроено в страницу, его байты входят в хеш страницы. Файл вставки в output не пишется и в contentHashes отсутствует.
  • mergeIncludes: false, hashIncludes: true (по умолчанию) — страница ссылается на вставку под подписанным именем inc-{12hex}.md. Изменение вставки меняет её хеш и переименовывает её, что меняет ссылку в странице, что меняет хеш страницы.

Алгоритм diff (на стороне потребителя):

changed_pages = {
  p ∈ entries(curr) |
       prev.contentHashes[p]?.hash ≠ curr.contentHashes[p]?.hash
    OR ∃ a ∈ curr.pageAssets[p]:
         prev.contentHashes[a]?.hash ≠ curr.contentHashes[a]?.hash
}

added_pages   = keys(curr.contentHashes) \ keys(prev.contentHashes)
removed_pages = keys(prev.contentHashes) \ keys(curr.contentHashes)

Пример выходного файла:

{
  "schemaVersion": 1,
  "contentHashes": {
    "ru/foo.md": { "hash": "sha256-...", "size": 1234 },
    "ru/foo/inc.md": { "hash": "sha256-...", "size": 567 },
    "ru/img/pic.png": { "hash": "sha256-...", "size": 8901 }
  },
  "pageAssets": {
    "ru/foo.md": ["ru/img/pic.png"]
  }
}

Известные ограничения

Случаи, когда ключи в contentHashes могут «дрожать» или быть шумными независимо от реального изменения содержимого. Они не мешают основным сценариям (переиндексация поиска, уведомления об изменениях), но о них стоит знать:

  • _bundle/* — пайплайн output-html копирует JS/CSS-чанки CLI в _bundle/, и хеш, зашитый в имена этих файлов, сдвигается при каждом апгрейде @diplodoc/cli. Потребители, сравнивающие две сборки, должны отфильтровывать ключи, начинающиеся на _bundle/.
  • _search/* — если включён локальный поиск, LocalSearchProvider пишет ресурсы по пути _search/<lang>/{timeOrigin}-resources.js, где {timeOrigin} — время старта сборки. Каждая сборка даёт новое имя файла и новый ключ. Стоит отфильтровывать _search/ или принимать этот шум.
  • mergeSvg: true (по умолчанию) — SVG, на который ссылаются как ![](logo.svg), инлайнится в тело страницы и остаётся отдельным файлом в output. Изменение SVG переключает сразу три сигнала: хеш страницы, хеш отдельного .svg и страницу через pageAssets. Чтобы избежать двойного счёта, используйте ![](logo.svg){inline=false}.