Обзор на Astro JS: опыт боевого проекта на 500+ тысяч страниц

от автора

Привет! В этой статье я — Антон Резников, Fullstack разработчик и Lead проекта из evilUnion, расскажу, как мы отказались от знакомого всем Next JS, не пожалели об этом и запустили один из самых крупных наших проектов на очень перспективном фреймворке — Astro JS.

В этой статье мы посмотрим, что из себя представляет Astro, чем он выделяется среди других метафреймворков, изучим его особенности, а далее на реальном примере пройдем весь путь построения мультиязычного сайта на 500+ тыс. страниц. Поехали 🚀

Что это такое AstroJS?

AstroJS — мета-фреймворк для построения web-приложений. Его одноклассники — NextJS и NuxtJS, которых я еще упомяну позже.

Киллер-фичи

Вот какие приятные особенности ждут разработчиков, которые используют Astro:

  1. Никакого JavaScript на клиенте по умолчанию. При запуске сайта без дополнительных настроек в браузере вообще не будет JavaScript, это гарантирует максимальную производительность и скорость загрузки сайта. А если JavaScript все-таки нужен, его доставку на клиент можно гибко настраивать и быть уверенным, что клиент получит только самый необходимый код только тогда, когда это действительно нужно.

  2. Островная архитектура. В документации это называется Astro Island. Здесь имеется в виду механизм, благодаря которому UI состоит из независимых блоков, каждый из которых внутри себя может использовать разные JavaScript UI фреймворки — React, Vue, Svelte. Эти острова одновременно могут иметь разные стратегии получения JS кода на клиент и шерить между собой состояния.

  3. Контроль стратегии рендера. Astro дает возможность выбора — Static Site Generation или Server Side Rendering. Серверные страницы можно пререндерить на сервере или генерировать их по запросу. А статичные страницы могут содержать SSR страницы как nested routes. Красота!

В Astro нам доступны

  • роутинг через файловую систему;

  • API роуты; middleware;

  • поддержка typescript;

  • возможность деплоя на собственном сервере через node js

  • деплой на cloudflare, netlify, vercel из коробки

  • оптимизация картинок

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

Отдельно стоит отметить, что Astro дает доступ к использованию современных браузерных API — таких как View Transition API, prefetch вместе с Speculation Rules API.

Что говорит коммьюнити о Astro js

Недавно вышел State of JS 2025 — ежегодный опрос разработчиков, который отслеживает тренды в JS-экосистеме. И Astro там выглядит очень уверенно.

В общем Tier List по всем библиотекам Astro попал в высшую категорию — S-tier, с показателем удовлетворённости (satisfaction) 94%. В S-tier в этом году вообще попало всего 6 инструментов: Vite (98%), Vitest (97%), Hono (95%), Playwright (94%), Astro (94%) и Bun (91%). Next.js для сравнения оказался в C-tier с показателем 55%.

Next.js показал наибольшее падение в удовлетворенности — с 68% до 55% — это самое серьёзное падение среди всех рассмотренных библиотек за год. И падает он с 2021 года с 91% каждый год

Падение NEXT JS

Падение NEXT JS

В разделе, посвящённом именно мета-фреймворкам, авторы прямо пишут: Next.js продолжает набирать популярность и доминировать в категории мета-фреймворков, но при этом парадоксальным образом теряет в удовлетворённости. А про сам Astro сказано так: Astro внимательно изучил, что делают другие статические генераторы, взял лучшие идеи и отбросил остальное — в результате получился фреймворк, который одновременно ощущается простым и мощным, и как следствие занимает первое место по удовлетворённости.

Распределение удовлетворенности пользователей среди meta фреймворков на изображении ниже:

Про рост популярности Astro авторы отчёта тоже высказались однозначно: достаточно взглянуть на график осведомлённости (Awareness), чтобы увидеть, насколько опасным конкурентом стал Astro — путь от практически полной неизвестности до серьёзного соперника занял всего несколько лет.

График Satisfaction

https://2025.stateofjs.com/en-US/libraries/meta-frameworks/#meta_frameworks_ratios

Использование

Использование

Так что цифры в целом подтверждают то, что мы наблюдаем и в своей практике — у Next.js остаётся преимущество по охвату аудитории, но по опыту использования и удовлетворённости разработчиков Astro сейчас один из лидеров рынка. А эти именно факторы могут сделать Astro в будущем самым популярным фронтенд фреймворком.

Давайте взглянем на цифры ближе:

У NextJS доля разработчиков, которые его использовали и оставили положительную оценку — 40%. У Astro этот показатель 67%.

Суммарная доля всех отрицательных отзывов о NextJS — 30%, в то время как у Astro — 13%.

Можно возразить, что Astro многие не использовали, но, во-первых, я здесь как раз-таки и занимаюсь его популяризацией, а во-вторых, даже среди таких разработчиков, доля положительных отзывов у Astro 30% против 16% у NextJS.

Факты налицо — у NextJS есть перспективный соперник.

Мы сделали большой проект

Мы реализовали крупный проект, использовав этот фреймворк. Кратко ТЗ можно озвучить следующим образом — нужен мультиязычный продукт на 500+ тыс. страниц, который будет очень быстрым.

Положительные моменты

Для начала разберем «технический сахар» — то, что нам понравилось в этом инструменте.

Конвертирование изображений

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

  • Формат изображения.

  • Качество изображения (относительно исходной картинки).

  • Размеры экранов, чтобы сделать несколько версий изображения для использования в srcset.

Преобразованные изображения сохраняются в папку проекта и далее запрашиваются только оттуда (нет fetch запросов на удаленные картинки).

Но, в отличие от того же NextJS, а в Astro нам доступен не только сам компонент Image, но и метод API, который используется этим компонентом — getImage() . С его помощью мы смогли использовать конвертированные изображения в React островах, а не только в Astro компонентах. Так можно использовать оптимизатор картинок Astro в компонентах UI фреймворков.

Возможность настроить получение JS кода на клиент

Эта опция дает возможность контролировать, как клиентские UI Framework компоненты получают код на страницу, доступные варианты:

---// Path: src/pages/hydration-example.astro    import StaticComponent from '../components/StaticComponent.astro';import InteractiveCounter from '../components/InteractiveCounter.jsx';import LazyLoadedComponent from '../components/LazyLoadedComponent.jsx';import HeavyComponent from '../components/HeavyComponent.jsx';---<html>  <head><title>Примеры гидратации JS на клиент</title></head>  <body>    <!-- Компонент без JavaScript на клиенте -->    <StaticComponent />        <!-- Доступные опции гидратации JS кода -->    <!-- 1. Загрузка JS сразу после загрузки страницы -->    <InteractiveCounter client:load />        <!-- 2. Гидратация после того, как компонент попадет во viewport -->    <LazyLoadedComponent client:visible />        <!-- 3. Гидратация когда страница загружена и браузер в состоянии "idle" -->    <HeavyComponent client:idle />        <!-- 4. Гидратация по медиа запросу -->    <div client:media="(max-width: 768px)">      This only hydrates on mobile devices    </div>        <!-- 5. Такой компонент будет рендериться только на клиенте  -->    <div client:only="react">      This renders only on the client    </div>  </body></html>

А теперь перейдем к практической части. Посмотрим детали, как мы реализовали проект.

Здесь мы будем фокусироваться только на фронтенд части, детали бекенда я буду раскрывать, если это потребуется для понимания сути (честно говоря, там и без фронтенда много интересного).

Стек

Для клиентской логики мы выбрали React, стили на CSS-in-JS библиотеке Linaria, а как серверный провайдер — NodeJS, так как мы сами занимаемся деплоем и используем SSR страницы.

Маршрутизация

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

В файле достаточно строк export const prerender = true чтобы использовать статическую генерацию:

---// статические роутыexport const prerender = true;export async function getStaticPaths() {}const { seoTitle, seoDescription, Sections} = Astro.props;---<Layout seoTitle={seoTitle} seoDescription={seoDescription}>   <CollectionPageStructuredData      slot="structured-data"      apiUrl={apiUrl}      collectionType={'category'}   />   <Constructor slices={Sections} /></Layout>

И export const prerender = false чтобы генерировать страницы на стороне сервера.

// SSRexport const prerender = false;const { country } = Astro.params;const currentLocale = Astro.currentLocale;const countryPageResponse = await fetchApiDynamic({   locale: currentLocale,   wrappedByKey: 'data',   query: getLocationPageQuery('country', country),});const page = countryPageResponse?.data?.[0];if (!page) {   errorPageRefererLog(Astro.url.href);   return Astro.redirect(`/${currentLocale}/404`);}---<CountryLayout page={page}  />

Далее, мы сделали Layoutдля каждого типа страниц, который у нас есть. И в конце мы получили систему роутов, которую легко масштабировать и поддерживать, потому что основной код прописан в файлах Layout, а настройки маршрутизации не заданы кодом, а контролируются из CMS. Эти несколько файлов позволяли контролировать более 500 тысяч маршрутов для страниц без вмешательства в код

📁 src├── 📁 layouts    ├── Layout.astro    ├── Maintenance.astro    ├── CountryLayout.astro    ├── RegionLayout.astro    ├── CityLayout.astro    └── ProjectLayout.astro

Некоторые функции, которые может интересны не всем.

Превью страниц

Как отдельную фичу, я выделю возможность посмотреть превью страницы из CMS до самой ее публикации. Это очень полезно для контент мейкеров и команды.

Эта возможность есть так же и в NextJS, но, на мой взгляд, она реализована там чересчур сложно для такого простого функционала.

В документации Astro вы не найдете пункта “Preview mode” или “Draft mode”, но это легко сделать самостоятельно. Опишу, как это сделали мы:

  • создали on-demand роут, который будет рендерить нужную страницу

  • запретили кеширование на уровне прокси-сервера на этом маршруте

  • защитили превью роут, чтобы он открывал такие ссылки только от нашего бекенда

Вот и все, после клика в CMS на кнопку “preview”, фронтенд получает все необходимые данные о странице, которую нужно показать, далее она отображается в iframe в CMS. Настройка простая и изменяемая при необходимости.

Storybook

Этот инструмент на проекте использовался одновременно и разработчиками, и контент-менеджерами из команды заказчика для визуальной ориентации, так как они создавали страницы сайта через конструктор в CMS.

Здесь стоит отметить, что мы отображали в Storybook только React компоненты, а не компоненты Astro

Опять, как и с превью, в документации Astro нет раздела интеграции со Storybook. Но сам Astro работает на сборщике Vite, поэтому интеграция опять же не заняла много времени.

Сама конфигурация только потребовала отдельной настройки для работы со стилями из Linaria, вот как выглядит конфиг Storybook:

import wyw from '@wyw-in-js/vite';import type { StorybookConfig } from '@storybook/react-vite';const config: StorybookConfig = {   stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],   addons: [      '@storybook/addon-essentials',      '@storybook/addon-onboarding',      '@chromatic-com/storybook',      '@storybook/experimental-addon-test',   ],   framework: {      name: '@storybook/react-vite',      options: {},   },   babel: {      presets: ['@linaria'], // нужно было сделать это   },   viteFinal: (config) => {      config.plugins = config.plugins || [];      config.plugins.push(wyw()); // и вот это      return config;   },};export default config;

Astro slots или удобный HTML Inject

В Астро этот механизм позволяет удобно встраивать компоненты Astro в другие, наподобие children в React, с поддержкой аргументов. Мы использовали эту возможность, чтобы встроить json/ld разметку в разные Layout:

// страница [category] без разметки<Layout seoTitle={seoTitle} seoDescription={seoDescription} isAccentHeader={isAccentHeader}>   <Constructor slices={Sections} typeName={typeName} /></Layout>

Добавляем разметку

// страница [category] с json/ld разметкой<Layout seoTitle={seoTitle} seoDescription={seoDescription} isAccentHeader={isAccentHeader}>   <CollectionPageStructuredData      slot="structured-data"      data={Astro.props}      apiUrl={apiUrl}      collectionType={'category'}   />   <Constructor slices={Sections} typeName={typeName} /></Layout>

Как выглядит сам компонент разметки:

// CollectionPageStructuredData.astro---const structuredData = prune({   '@context': 'https://schema.org',   '@type': 'CollectionPage',   name: pageName,   description: pageDescription,   url: canonicalUrl,   // ... other});---<script type="application/ld+json" set:html={JSON.stringify(structuredData)} />

Как мы видим, таким способом можно легко расширять готовые Layout компоненты.

Глобальный store

Работа с глобальным состоянием в Astro (с использованием React в нашем случае) уже отличается от привычного подхода в экосистеме React.

Так как Astro Island — это независимые между собой блоки, где не везде есть React, привычные Zustand или Redux здесь не подходят. В документации рекомендуется библиотека nanostores, которую мы и использовали для хранения глобального состояние и шеринга его между разными React компонентами. Эта библиотека не зависит от используемого UI фреймворка.

Вот так мы создаем глобальный store:

import { atom } from 'nanostores';export const blogCategoryStore = atom('All');

А дальше используем его в React компонентах

const handleChooseCategory = (name) => () => blogCategoryStore.set(name);

С какими негативными моментами столкнулись

Не поддерживается React Context между островами

Astro не поддерживает работу с React Context между разными Astro Island. Это значит, к примеру, что использование React UI библиотек (Mantine, MaterialUI) невозможно. В таком случае придется искать альтернативу, либо использовать UI библиотеки изолированно, только в нужных React островах.

Аутро

В целом, AstroJS показал себя отлично. Документация очень подробная и богата различными примерами и use cases. Впечатления остались положительные. Приятно также то, что инструмент интуитивно понятен.

До перехода на этот фреймворк мы работали с Gatsby и Next, где на протяжении разработки сталкивались с теми или иныни проблемами. Нельзя сказать, что мы не решили эти проблемы в итоге, но с Astro работа шла приятнее, без подводных камней.

Используя Astro, намного легче добиться 100 баллов performance в Google Lighthouse. О скорости и производительности своих сайтов посвящено несколько блоков на главной странице Astro, что подтверждается в том числе нашими результатами Lighthouse.

Следует помнить при работе с Astro. Вы не обязаны использовать React

Всегда ли вам нужна клиентская логика в компонентах? На самом деле нет. На сайте может быть достаточно большое количество блоков, которые не имеют клиентской логики — они просто отображают данные из CMS в виде ссылок/текста. Такие компоненты нужно оформлять в .astro файлах, без React. Это также снизит вес бандла и улучшит производительность.

Чтобы это наглядно увидеть, я провел тест — сделал 2 проекта Astro, добавил туда 2 одинаковых компонента без клиентской логики. Один сверстал на Linaria + React, другой на Linaria в Astro компоненте. Сбилдил оба проекта и запустил, чтобы проверить вкладку Network

Результаты оказались следующими для Astro компонента:

Клиент вообще не получил JS кода, так как его нет.

Для компонента на React:

Мы видим 3 скрипта и увеличенный вес html страницы. 2 скрипта это код React, третий — код самого компонента.

Итоговый вес страницы без React более чем в 3 раза меньше чем с ним.

Поэтому нужно отказываться от лишнего. Компоненты без логики могут и должны быть только HTML разметкой со стилями. Это и проще, и производительнее.

Переиспользуемый JS

Также мы проверили и убедились в том, что ядро React и общие функции/utils переиспользуются на клиенте. Astro не тянет на клиент несколько копий функции, если они используются в разных островах, это важно.

Кеш серверных страниц

Недавно Astro обновился до новой мажорной версии 7, где были добавлены интересные нововведения, а именно возможность кеширования SSR страниц с ревалидацией. Стандартный пакет включает только memory cache provider, но свои писать тоже возможно. Также там переписали (конечно же на Rust) и ускорили компилятор. С полным changelog можно ознакомиться здесь.

Итого

Спасибо за внимание, делитесь опытом работы с Astro в комментариях, будет интересно узнать, какие проблемы вам удалось (или не удалось) решить.

А если вы планируете запускать проект на Astro или ищете команду, которая уже имеет опыт разработки и эксплуатации крупных проектов, мы в evilUNION создаем сайты и веб-приложения на Astro и всегда готовы обсудить интересные задачи.

ссылка на оригинал статьи https://habr.com/ru/articles/1061810/