IKORG
English

← Практика · 31 августа 2026

Как разложить 10 000 страниц в Astro и не сломать сборку

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

8 минут чтениясайты

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

Пишу по опыту живого проекта: справочный сайт на Astro, сейчас в нём три с половиной тысячи страниц, растёт дальше. Всё ниже — то, обо что я споткнулся сам.

Почему статический генератор, а не CMS

Для справочного сайта — каталога, словаря, базы кратких содержаний, карточек товаров без корзины — контент меняется редко, а читают его много. Это ровно тот случай, где CMS работает против вас: на каждый заход поднимается PHP, ходит в базу, собирает страницу, которая не менялась полгода. Дальше начинается лечение симптомов: кеш, потом кеш кеша, потом «почему у нас снова слетел кеш».

Статический генератор собирает те же страницы один раз и кладёт готовый HTML. Сервер отдаёт файл. Никакой базы в проде, нечего взламывать, нечему падать под нагрузкой, хостинг — самый дешёвый.

CMS честно выигрывает в двух случаях: контент правят несколько человек без доступа к репозиторию, или страницы персональные (личный кабинет, корзина, цены под пользователя). Если этого нет — статика.

Astro тут удобен тем, что по умолчанию отдаёт ноль килобайт JavaScript, а компоненты можно писать как обычный HTML. На большом справочнике это важнее модных фич: страница должна открываться мгновенно на телефоне в метро.

Как раскладывать контент

Главное правило: страница — это данные плюс шаблон, а не файл, который кто-то написал руками. Десять тысяч файлов .astro никто не поддержит.

Данные держите отдельно: JSON, YAML или Markdown с полями. Дальше один динамический маршрут разворачивает их в страницы:

src/
  pages/
    произведения/[work].astro     ← один шаблон на все карточки
    авторы/[author].astro
    index.astro
  data/
    работы/*.json                 ← данные, по файлу на сущность
// src/pages/произведения/[work].astro
export async function getStaticPaths() {
  const работы = await Astro.glob('../../data/работы/*.json');
  return работы.map((р) => ({
    params: { work: р.адрес },
    props: { работа: р },
  }));
}
const { работа } = Astro.props;

Три вещи, которые стоит решить один раз и не менять:

Адреса. Латиница, транслит, без дат в пути. Адрес страницы — это навсегда: переименование через год означает редиректы, потерянные ссылки и просевший поиск.

Плоская или вложенная структура. Для десяти тысяч страниц лучше плоская с осмысленными разделами (/произведения/имя/, /авторы/имя/), а не пятиуровневая иерархия. Глубина усложняет навигацию, ломает хлебные крошки и делает адреса длинными.

Что считается на сборке, а что лежит в данных. Всё, что можно посчитать заранее — счётчики, связи, «похожие материалы», — считайте один раз скриптом и кладите в данные. Иначе десять тысяч страниц будут пересчитывать одно и то же на каждой сборке.

Что ломается на масштабе

Сборка растёт линейно, а память — нет. Пока страниц пара сотен, сборка идёт секунды. На тысячах это уже минуты, и главный пожиратель — не HTML, а обработка изображений. Если на каждой странице по картинке через встроенный оптимизатор, вы получите десять тысяч операций с картинками при каждой сборке. Лечится просто: обрабатывайте медиа отдельным скриптом один раз, кладите готовые файлы рядом и подключайте как статику. Правило: в сборке не должно быть ничего, что можно сделать заранее.

Не грузите весь набор данных на каждой странице. Astro.glob по десяти тысячам файлов внутри шаблона страницы — это десять тысяч чтений каталога. Собирайте общие данные один раз в getStaticPaths и передавайте в props только то, что нужно конкретной странице.

Списки нужно резать на страницы. Каталог из десяти тысяч ссылок на одной странице — это мегабайты HTML, которые никто не пролистает. Встроенная пагинация Astro делает это в несколько строк:

export async function getStaticPaths({ paginate }) {
  const все = await получитьВсе();
  return paginate(все, { pageSize: 50 });
}

Диск кончается раньше терпения. У меня папка сборки на три с половиной тысячи страниц весит 1,2 гигабайта — в основном из-за медиа. На маленьком VPS это половина свободного места. Держите медиа отдельно от сборки и не заливайте их каждый раз заново.

Поиск

Клиентский поиск по десяти тысячам страниц — отдельная ловушка. Наивный подход «соберём один JSON со всеми текстами» даёт индекс в десятки мегабайт, который браузер честно скачает на телефоне.

Рабочих варианта два.

Резаный индекс. Держите в индексе только заголовки, ключевые слова и адрес — без полных текстов. Для справочника этого обычно достаточно: люди ищут название, а не фразу из середины.

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

npx pagefind --site dist

Что бы вы ни выбрали — проверьте вес того, что скачивает браузер. Это единственная метрика, которая тут имеет значение.

Карта сайта

Стандарт запрещает больше 50 000 адресов в одном файле. На десяти тысячах вы ещё влезаете, но лучше сразу поставить официальный плагин — он сам разложит карту на части и сделает файл-индекс:

// astro.config.mjs
import sitemap from '@astrojs/sitemap';
export default defineConfig({
  site: 'https://example.ru',
  integrations: [sitemap()],
});

Не забудьте site — без него ссылки в карте будут относительными, и поисковик её не примет.

Выкладка

Здесь у большинства и болит. Собранный сайт — это десятки тысяч мелких файлов. Заливать их целиком на обычный хостинг по SFTP — час времени и высокий шанс, что соединение оборвётся на середине.

Заливайте только изменившееся. Если есть SSH — rsync -a --delete dist/ сервер:/путь/. Если хостинг даёт только SFTP, ведите манифест: складывайте контрольные суммы файлов после каждой выкладки и отправляйте лишь те, у которых сумма изменилась. У меня скрипт выкладки принимает список путей и льёт ровно их — обычная правка задевает три-четыре файла вместо десяти тысяч.

Медиа не трогайте. Картинки и аудио заливаются один раз и лежат. Перезаливать их вместе со сборкой — самая частая причина «деплой идёт сорок минут».

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

Когда Astro — не лучший выбор

Если страниц не десять тысяч, а сто тысяч и больше, посмотрите на Hugo: он собирает такие объёмы за секунды, потому что написан на Go, и разница становится решающей. Расплата — менее приятный шаблонизатор.

Если контент меняется ежечасно и ждать сборку нельзя, нужен рендер по запросу с кешем — Next.js и его инкрементальная перегенерация.

Если контент правят не разработчики, добавьте к статике «безголовую» CMS, но оставьте сборку статической: редактор пишет в админке, сборка запускается по кнопке, наружу по-прежнему отдаётся готовый HTML.

Во всех остальных случаях статика скучна, дёшева и работает годами без вашего участия. Для справочника на десять тысяч страниц это ровно то, что нужно.