Перевірки
Зелена збірка ще не означає, що сторінки в порядку. Цей інструментарій ставить по одній перевірці на кожен шар, і кожна ловить свій клас тихих відмов «збірка зелена — сторінка зламана», а дві з них дивляться на сторінки так, як читач: у справжньому браузері.
§1П’ять заслон, п’ять шарів
| Перевірка | Постачається з | Дивиться на | Коли запускати |
|---|---|---|---|
| check-content | рушій, scripts/check-content.mjs | кожне джерело md/mdx | CI репозиторію вмісту або одразу після написання |
| check-wikilinks | рушій, scripts/check-wikilinks.mjs | граф [[вікіпосилань]] | CI репозиторію вмісту або після перейменування нотатки |
| check-dist | рушій, scripts/check-dist.mjs | вивід astro build | після кожної збірки (postbuild) |
| ui_probe | цей пакет, scripts/ui_probe.mjs | сторінки, відрендерені у справжньому браузері | після змін стилів чи макета |
| contrast_probe | цей пакет, scripts/contrast_probe.mjs | контраст кожного текстового вузла, обидві теми | після будь-якої зміни токенів |
§2check-content: шар джерел
Компілює кожен md/mdx, якому судилося стати сторінкою, точно тим самим діалектом, що й сайт: синтаксичні помилки й тихі деформації (маркери виділення, яким немає пари; дужки, проковтнуті обчисленням MDX; маркери списків, народжені перенесенням рядка; однорядкове $$; формули, які KaTeX не рендерить, — той самий перелік, яким закінчується демонстраційний стенд) роблять CI червоним.
Чому цей скрипт мусить походити з рушія: перевіряльник, чий набір плагінів відрізняється від сайтового, гірший за жодного — без плагіна математики він читає дужки формул як вирази JSX, без GFM пропускає таблиці повз. Діалект написано один раз, у рушії; рендеринг сайту, валідація збережень CMS і цей скрипт споживають той самий — завжди.
node <engine>/scripts/check-content.mjs . --glob '**/index.{md,mdx}' --mathПоза компіляцією він ловить два frontmatter-класи тихих втрат: незалапкований # у значенні (YAML читає його як коментар і мовчки обрізає решту) та YAML, який узагалі не парситься, — обидва зі згадкою рядка у звіті.
§3check-wikilinks: граф посилань
Мертві [[вікіпосилання]] навмисно не валять збірку: сад мусить мати право посилатися на нотатки, які ще не виросли. Але гниття посилань усе одно має жити в CI, тож рушій постачає лінт, який розв’язує кожне вікіпосилання парсером і правилами самої бібліотеки (псевдонім, бренд, заголовок, мовні дзеркала) і звітує про відсутні цілі, неоднозначності та сумнівні якорі. --strict перетворює мертві посилання на ненульовий код виходу — саме так це запускає CI цього репозиторію:
node scripts/check-links.mjs§4check-dist: шар виводу
У зібраному dist/ кожне внутрішнє посилання, на яке читач може клацнути, мусить справді існувати. Перевірка ловить тихі провали під зеленою збіркою:
- внутрішні посилання й ресурси, що вказують на неіснуючі файли (після перекроювання маршрутів такі з’являються десятками);
- якорі в межах сторінки, що вказують на неіснуючі id;
- подвоєні мовні сегменти в шляхах (
/en/en/— класичний наслідок того, що i18n-фолбеки нашаровують префікс на вже префіксовані маршрути); <a>, вкладений в<a>(HTML-парсер закриває зовнішній передчасно, і кнопки випадають зі своїх карток);- рештки помилок KaTeX (формула стоїть на сторінці червоним текстом, а збірка тим часом зелена).
Це демо вмикає його у postbuild: зелений npm run build означає, що перевірка виводу теж пройшла.
node vendor/astro-inkbrush/scripts/check-dist.mjs dist --base ${DEMO_BASE:-/}§5Зонд шару рендерингу
Джерело й вивід можуть бути бездоганними, а сторінка — все одно зламаною; класичний випадок — картки головної, до яких не дотягується жодне правило стилів, тож вони рендеряться одним затиснутим рядком голого тексту: перевірки посилань і якорів лишаються зеленими, бо на відрендерену сторінку вони не дивляться взагалі. ui_probe проганяє справжній браузер по кожній сторінці dist на чотирьох ширинах вікна (1440/1024/768/430) і вимірює: горизонтальне переповнення сторінки, елементи ширші за контейнер без прокручуваної рамки, класи, які не стилізує жодне правило, пропущені рівні заголовків, повторені id, зображення без атрибута alt, якорі в межах сторінки й aria-controls, що вказують у порожнечу. Він звітує лише те, що машина може довести, — без естетичних суджень.
npm run build
node ../scripts/ui_probe.mjs dist # сам роздає dist; передайте baseUrl, щоб зондувати живий серверВін оглядає документ цілком — разом з оздобленням, бічною панеллю та діалогами.
Зелений результат — коли останній рядок звіту читається SAMPLES WITH FINDINGS: 0
(семпл — це один маршрут на одній ширині).
§6Зонд контрасту
Токени заявляють AA, тож заявку вимірюють, а не стверджують. contrast_probe відкриває кожну сторінку dist у справжньому браузері — світла й темна теми, ширина настільного екрана та телефона — і вимірює кожен текстовий фрагмент, відрендерений у типовому стані: текст HTML, текст SVG і згенерований текст ::before / ::after, причому на представницькій сторінці кожен оверлей <dialog data-probe-open> зондовано відкритим (і з набраним у знайденому там полі пошуку запитом) — цей маркер є заявою сайту, що діалог завершено таким, як його написано. Тло не читається з таблиці стилів: сторінку рендерять з усіма гліфами, зробленими прозорими, знімають скріншот, і піксель під кожним фрагментом стає його тлом — тож градієнти, відтінки color-mix(), напівпрозорі шари й нічну палітру виміряно такими, якими вони рендеряться. Передній план фрагмента несе накопичену opacity елемента і предків, тож пригашений текст виміряно на тій силі, яку читач бачить насправді. Стани наведення й фокуса переглядають очима, а не зондом. Дрібний текст тримають на 4.5:1, великий (24px або 18.66px жирним) — на 3:1; фрагмент, чий колір не вдалося розібрати або чиє тло не вдалося зняти, рахується знахідкою. Звіт називає сторінку, тему, ширину, селектор, обидва кольори та коефіцієнт кожного фрагмента нижче планки:
node ../scripts/contrast_probe.mjs dist # PROBE_THEMES / PROBE_WIDTHS звужують матрицюui_probe і contrast_probe по виводу — все зелене до коміту. Демо водночас слугує пакетові випробувальним стендом.