Стартер мой, поэтому текст ниже устроен так: сначала что в нем правда хорошо, потом чего в нем нет вовсе, и в конце то, на чем я споткнулся сам, собирая на нем этот блог. Хвалить свое легко, поэтому вторая и третья части длиннее первой.

proxima812/astro-starterОснова для SEO-ориентированных статических сайтов.

Что это по цифрам

1683 строки в src, 8 Astro-компонентов, 3 страницы, 6 интеграций, 13 зависимостей и 5 дев-зависимостей. Репозиторий создан в апреле 2026, последняя правка в августе, три звезды, один автор. Это не фреймворк и не тема, а заготовка на пару вечеров работы, которую не хочется писать заново каждый раз.

Стек без сюрпризов: Astro 7 в статике, Tailwind v4 через @tailwindcss/vite, TypeScript в строгом режиме, Biome вместо ESLint и Prettier, Bun как пакетный менеджер.

Идея: один файл под правку

Главное решение стартера - весь проект настраивается из main.config.ts, и это 98 строк. Там URL, название, локали, Open Graph, цвета темы, подтверждения владения доменом, аналитика и флаги фич.

Звучит как обычный config.js, но разница в том, что рядом лежат две вещи: контракт в src/config/types.ts и проверки в src/config/validate.ts, которые падают на старте dev и build.

TypeScript
export type AnalyticsProvider<TId> =
	| { readonly enabled: false }
	| { readonly enabled: true; readonly id: TId };

Это дискриминированный union, и он делает невозможной целую категорию ошибок: включить аналитику без идентификатора нельзя, потому что не скомпилируется. То же самое с IndexNow, который без ключа существовать не может.

Прием не новый, но в стартерах он встречается редко: обычно конфиг это объект с десятком необязательных полей и абзац в README о том, какие из них обязательны, когда включена такая-то фича. Здесь эту роль выполняет компилятор.

Проверка сборки, а не намерений

Второе, что стартер делает всерьез, - bun run verify. Это линт, типы, сборка и 177 строк валидатора, который открывает каждую страницу в dist и проверяет:

  • есть ли <title> и мета-описание,
  • есть ли canonical,
  • на месте ли набор Open Graph,
  • парсится ли JSON-LD как JSON,
  • проставлен ли <html lang>,
  • сколько на странице h1,
  • стоит ли noindex на 404,
  • существуют ли в dist все локальные ссылки на ассеты.

Разница между «я добавил мета-теги» и «в собранном HTML они есть» - это ровно та разница, из-за которой SEO-правки обычно уезжают незамеченными. Валидатор проверяет второе.

Фичи выключаются честно: enabled: false не оставляет ни файла в dist, ни тега в HTML, ни строки в robots.txt. Я проверял это на своей правке - добавлял комментарии и прогонял сборку в обоих состояниях флага. Ноль следов.

Агентский слой

В репозитории лежат AGENTS.md и девять скиллов в .agents/skills/: архитектура, стиль кода, зависимости, разработка фич, i18n, SEO, Tailwind, TypeScript, валидация. Симлинки в .claude/skills/ дают тот же набор Claude Code и Codex.

Это не украшение. Скилл starter-tailwind прямо запрещает хардкодить цвета мимо токенов, starter-dependencies перечисляет удаленные пакеты и причины, чтобы их не вернули обратно, starter-validation описывает, что считать выполненной задачей. Агент, который читает эти файлы, ведет себя в проекте предсказуемее, чем без них.

Чего в нем нет

Дальше честная часть.

Лицензии нет. У репозитория не проставлена лицензия вообще. Формально это значит, что права не переданы никому: клонировать «стартер» и строить на нем коммерческий проект юридически нельзя. Для заготовки, которую создают ровно затем, чтобы ее клонировали, это самая крупная недоделка.

CI нет. Папки .github в репозитории нет. bun run verify существует, но ничто не мешает запушить сломанную сборку - проверка держится на дисциплине.

Тестов нет. Ни одного файла с тестами. Для 1683 строк, где половина - генерация артефактов и валидация конфига, это заметно: и валидатор конфигурации, и SEO-чекер - это ровно тот код, который тестируется легко и окупается быстро.

Репозиторий не помечен как template. «Use this template» на GitHub не работает, остается клонировать и отвязывать историю руками. При этом история - один коммит, то есть посмотреть, что менялось между версиями, нельзя.

Контента нет вообще. Ни content collections, ни примера блога, ни mdx файла - при том, что @astrojs/mdx в зависимостях есть. Три страницы: главная, ее английская версия и 404.

Темной темы нет. В токенах одна палитра.

Несколько зависимостей стоят «на вырост». @iconify-json/mdi не используется ни разу, astro-icon подключен с пустым include: {}, @tailwindcss/typography загружен через @plugin, но класс prose в стартере не встречается. На вес готового сайта это не влияет - Tailwind v4 генерирует классы по факту использования, а Astro не бандлит неиспользуемое, - но в установке и в списке зависимостей они есть.

На чем я споткнулся

Этот блог собран на стартере, и три вещи всплыли только в реальной работе.

Сборка на Cloudflare Pages падает из коробки

Самое серьезное. @dualmark/astro@0.10.0 - последняя версия - объявляет peer astro@^6.1.10, а в стартере стоит Astro 7. Bun такой конфликт пропускает молча, поэтому локально все ставится и работает. Cloudflare Pages ставит зависимости через npm install и падает:

TXT
npm error ERESOLVE unable to resolve dependency tree
npm error Found: astro@7.2.4
npm error Could not resolve dependency:
npm error peer astro@"^6.1.10" from @dualmark/astro@0.10.0

Деплой не начинается вообще. Лечится файлом .npmrc с legacy-peer-deps=true или переключением сборки на Bun в настройках хостинга, но узнать об этом можно только на первом деплое. В стартере ни того, ни другого нет.

Блог придется писать целиком

Ожидаемо, но масштаб я недооценил. Чтобы получить обычный блог, поверх стартера пришлось написать: описание коллекции, выборку постов, карточку, сетку, компонент статьи, стили для всех тегов markdown, подмену тегов через components у <Content />, компоненты иллюстрации и галереи, обертку таблицы с прокруткой и блок кода с шапкой. Это десяток файлов и несколько часов.

Стартер про SEO-каркас, а не про контент, и в README это сказано. Но если вы идете за блогом - вы идете не за этим.

Сборка markdown-двойников требует ручной работы

llms.txt и markdown-версии страниц собираются из явно перечисленных staticPages и sections в astro.config.mjs. Добавили страницу - идите дописывать ее в два места, иначе она в двойники не попадет. README об этом предупреждает честно, но это ровно тот вид ручной синхронизации, который разъезжается первым.

Линт покрывает не все

biome.json исключает public/ и src/components/SEO/Analytics/**, и на это есть причины: Biome переформатирует SVG в public/ и не парсит инлайновый JavaScript внутри .astro - поддержка .astro у него экспериментальная. Причины задокументированы в AGENTS.md, но факт остается: часть кода вне проверки.

Кому подходит

Подходит, если вы делаете статические сайты на Astro регулярно и одинаково: лендинги, корпоративные страницы, документацию. Тогда стартер экономит несколько вечеров на SEO-обвязке, которую иначе каждый раз пишешь заново и каждый раз забываешь половину.

Подходит, если вам близка идея, что конфигурация должна проверяться компилятором, а результат - валидатором по dist, а не глазами.

Не подходит, если нужен готовый блог, набор UI-компонентов или тема. Здесь их нет и не планируется - это каркас, а не витрина.

Не подходит, если нужна юридическая чистота: без лицензии брать чужой код в коммерческий проект нельзя.

Что бы я исправил первым

По убыванию важности: лицензия, .npmrc или документированный способ собрать на npm-хостинге, GitHub Actions с bun run verify, тесты на валидатор конфигурации и SEO-чекер, отметка репозитория как template.

Первые два - это полчаса работы, и они превращают заготовку «для себя» в заготовку, которую можно давать другим.

Исходники стартераAstro 7, Tailwind v4, TypeScript strict, Bun.