taiga
руководство · разбор

Обложки, поиск и другая магия сборки

проверено на v0.0.1 ~6 мин 582 слова

Обложка для соцсетей, полнотекстовый поиск и чип версии в мете статьи выглядят как рантайм-магия — но происходят целиком на сборке. Разберём все три механизма: у каждого простое устройство и одна честная оговорка.

#Обложка без дизайнера

Наивная модель: обложки для шаринга рисуют руками. На тридцатой статье это боль, а после переименования заголовка — боль вдвойне: картинка теперь врёт, перерисовывай.

Здесь обложки генерирует сборка, а внешний вид описывает стиль — папка в assets/og/, имя папки = ключ стиля. Внутри два обязательных файла: base.png — подложка 1200×630, где живёт вся графика, и layout.toml — раскладка текстовых блоков поверх неё:

assets/og/dots/layout.toml (фрагмент)
[[block]]
text = "{title}"
font = "Inter-ExtraBold.ttf"
size = 66
color = "#e6dfd2"
x = 76
y = 270
width = 1010     # автоперенос длинных заголовков

Плейсхолдеры — {title}, {kicker}, {meta}, {domain}, {part} — собирает партиал, так что стиль языко-нейтрален: тексты приходят из статьи, раскладка — из стиля. Блоки рисуются по порядку; неизвестные ключи игнорируются — старый стиль переживёт новую версию темы. Опциональный home.png — полностью запечённый постер для главной и рубрик; если его нет, общая обложка генерируется тем же пайплайном из base.png. А папка без layout.toml стилем просто не считается.

Выбирается стиль параметром сайта ogImages.style, для отдельной страницы — og_style во front matter. А поверх любого стиля работает авторский оверрайд: положи og.png в бандл статьи — и генератор уступит место твоей картинке. Свой стиль сайт добавляет папкой: ассеты темы и сайта мержатся, сайт побеждает.

Ловушка

Текст на обложке рисует движок картинок Hugo, и у него есть пределы: межбуквенный интервал не поддерживается (аппроксимируется кеглем), а выравнивание вправо работает только для моноширинных шрифтов — ширина строки считается по числу символов. Дизайнь стили с этим в голове, а не выясняй на готовой обложке.

Наивная модель поиска на статике — индекс из заголовков и описаний: он найдёт статью по названию и промолчит про термин из середины текста. Здесь движок другой: Pagefind строит полнотекстовый индекс по уже собранному сайту. Поэтому сборка — две команды:

полная сборка сайта
hugo && pagefind --site public

Pagefind — standalone-бинарь, Node не нужен. Он проходит по готовому HTML и берёт только то, что размечено темой: тело статьи — целиком, крошки и минуты для карточки результата — отдельными метаданными, а панели, виджеты и прочий хром в индекс не попадают вовсе. Код-блоки индексируются с пониженным весом: поиск по имени функции обязан работать, но код не должен забивать выдачу. Русская морфология — из коробки, по языку страницы: запрос «обложек» найдёт «обложка». Скрипт поиска и сам индекс грузятся лениво, при первом открытии модалки: пока не искал — не скачивал ни байта.

Проверь на этой странице: открой поиск и набери слово из середины текста — например, «кегль». Найдётся, с подсветкой и выдержкой. А если запустить голый hugo server без второй команды, модалка честно подскажет, чем индекс собирается, — тихо, без красных ошибок.

Главная мысль

Все три механизма — build-time. Браузеру достаются готовая картинка, готовый индекс и готовая строка; в рантайме никто ничего не вычисляет и ни к каким сервисам не ходит.

#Чип версии

В мете этой статьи стоит чип «v0.0.1». Тема понятия не имеет, что это значит: чип — произвольная строка из version во front matter, а если поля нет — из versionDefault сайта. Сайт про язык программирования напишет туда версию языка, сайт про базу данных — «PostgreSQL 17», а это демо пишет версию самой темы — и тема рендерит всё одинаково, как есть. Маленькая деталь, но именно из таких складывается агностичность: тема не знает, о чём твой сайт.

Теперь ты можешь собрать сайт с обложками и полнотекстовым поиском двумя командами — и объяснить, почему команд именно две.

#Что дальше

Это был взгляд снаружи — что сборка делает для читателя. Взгляд изнутри — как устроены сами страницы — в серии «Анатомия темы»: про папки-бандлы, арифметику серий и палитры-файлы.