Обсудить задачу

Почему сайт на React теряет позиции в Google, и при чём тут архитектура

Сайт на React теряет позиции в Google не из-за самого React, а из-за того, как именно он отдаёт браузеру страницу. Если пользователь и поисковый робот получают почти пустой HTML-каркас, а весь контент достраивает JavaScript уже в браузере, первая отрисовка задерживается, и Googlebot откладывает полноценный рендеринг такой страницы в очередь. Решает не выбор фреймворка, а стратегия рендеринга - клиентская, серверная или статическая.

В проектах миграции сайтов мы в Exceltic.dev регулярно видим одну и ту же картину: сайт написан на чистом React через Create React App или Vite, без серверного рендеринга, PageSpeed показывает LCP выше 4 секунд на мобильном тесте, а часть страниц месяцами не попадает в индекс Google. Разработчики почти всегда списывают это на версию фреймворка, устаревший кэш или недостаточную SEO-разметку, хотя причина обычно глубже - в модели рендеринга, выбранной ещё на старте проекта.

Ниже - что физически происходит в браузере и в очереди Googlebot, когда сайт построен как SPA на чистом React, почему это бьёт сразу по двум метрикам Core Web Vitals, и почему решает не бренд фреймворка, а архитектура рендеринга - SSR, SSG или island-подход.

Боль редко заметна сразу. На быстром ноутбуке разработчика с горячим кэшем сайт открывается мгновенно. У реального посетителя с мобильной сетью первый контент показывается через несколько секунд пустого белого экрана - и поисковый робот видит ту же картину, но с ещё большей задержкой.

SPA (single-page application): архитектура, при которой браузер один раз загружает HTML-документ, а весь дальнейший контент и переходы между страницами формирует JavaScript на стороне клиента, без перезагрузки страницы.

MPA (multi-page application): архитектура, при которой каждый URL отдаёт с сервера отдельный, уже готовый HTML-документ, а переход между страницами - это полноценный новый запрос к серверу.

Что видит браузер, когда сайт - это чистый SPA на React

В классическом CRA-стиле SPA сервер отдаёт HTML-документ, в котором нет почти ничего - только пустой <div id="root"></div> и тег <script> с ссылкой на JS-бандл. Контент появляется только после того, как этот бандл пройдёт четыре последовательных шага: скачается, распарсится, выполнится и построит дерево компонентов в браузере.

Разница между ответом сервера у SPA и у SSR
<!-- Чистый CSR SPA: ответ сервера -->
<body>
  <div id="root"></div>
  <script src="/static/js/bundle.a1b2c3.js"></script>
</body>

<!-- SSR/SSG: тот же URL, ответ сервера -->
<body>
  <div id="root">
    <h1>Заголовок страницы</h1>
    <p>Контент уже здесь, до выполнения единой строки JS</p>
  </div>
  <script src="/static/js/bundle.a1b2c3.js"></script>
</body>

LCP (Largest Contentful Paint): момент, когда в области видимости отрисовывается самый крупный содержательный элемент страницы - обычно заголовок или hero-изображение. По данным web.dev, хорошим результатом Google считает LCP до 2,5 секунды.

В чистом SPA элемент LCP физически не может отрисоваться быстрее, чем закончится вся цепочка загрузки бандла. На быстром Wi-Fi это не всегда заметно. На мобильной сети с задержкой 3G или слабом процессоре бюджетного смартфона каждый из четырёх шагов растягивается, и суммарная задержка до первой отрисовки легко переваливает за 4-5 секунд.

Почему та же архитектура давит на INP

INP (Interaction to Next Paint): метрика, заменившая FID в марте 2024 года. Она измеряет время от клика или тапа пользователя до того, как браузер отрисует видимый отклик. Порог хорошего результата - до 200 миллисекунд.

После того как контент SPA наконец отрисован, фреймворку ещё нужно навесить обработчики событий на каждый интерактивный узел - этот процесс называется гидратацией. Пока он идёт, основной поток браузера занят, и клики, скролл, анимации откладываются в очередь. По независимым замерам гидратация страницы из полутора тысяч React-узлов блокирует основной поток на 150-300 миллисекунд - и это без учёта времени, ушедшего на сам первый рендер.

На маркетинговом сайте с несколькими виджетами - калькулятором, чатом, формой подписки - гидратация каждого из них добавляется к общей задержке. Пользователь видит кнопку, нажимает на неё, но обработчик ещё не подключён - и Chrome фиксирует это как плохой INP.

Почему React-сайт медленно индексируется в Google

Google обрабатывает JavaScript-страницы в два прохода. Первый проход происходит почти сразу и разбирает исходный HTML-ответ сервера - ссылки, метаданные, весь текст, который уже есть в разметке без выполнения скриптов.

Второй проход - непосредственно рендеринг через Web Rendering Service (WRS), headless-сборку Chromium, которую использует Googlebot для выполнения JavaScript. Этот проход не мгновенный: он встаёт в очередь и ждёт освобождения ресурсов рендеринга. По данным официальной документации Google Search Central, рендеринг может занять существенно больше времени, чем первичное сканирование, а конкретная задержка зависит от размера сайта и его текущего краулингового бюджета.

Практическое следствие: контент, который появляется на странице только после выполнения JS, может быть проиндексирован с задержкой или частично - особенно если домен новый или ещё не накопил высокий приоритет в глазах Googlebot. Контент, который уже есть в исходном HTML-ответе, участвует в первом проходе сразу, без ожидания очереди рендеринга.

При чём тут архитектура, а не бренд фреймворка React

Выбор между SPA и MPA - это выбор, где именно строится HTML: только в браузере пользователя или ещё и на сервере до того, как страница туда попадёт. Современные подходы не заставляют выбирать одну крайность.

Next.js с SSR или SSG решает проблему на уровне ответа сервера: HTML с уже готовым контентом, включая элемент LCP, приходит в первом же ответе, а гидратация React довешивается поверх готовой разметки, а не строит её с нуля. Разница между этими двумя режимами и Server Components подробно разобрана в статье Astro Islands vs Server Components.

Astro с island-архитектурой идёт дальше: страница по умолчанию отдаётся как статический HTML вообще без JavaScript, а React или любой другой UI-фреймворк подключается только к конкретным интерактивным островам - форме, калькулятору, чату - а не ко всей странице целиком. Прямое сравнение сценариев, где каждый подход выигрывает, - в статье Next.js vs Astro для маркетингового сайта.

В обоих случаях React остаётся частью стека. Меняется не фреймворк, а то, кто и когда строит первый HTML - сервер заранее или браузер пользователя в реальном времени.

Реальный кейс - что меняется при переходе с CSR на SSR или SSG

В типовом проекте миграции с чистого CSR SPA на Next.js с SSR или на Astro мы обычно фиксируем падение LCP с 4-5 секунд до 1,5-2,5 секунды на мобильном тесте PageSpeed Insights - потому что HTML с контентом приходит от сервера сразу, без ожидания загрузки и выполнения бандла.

INP улучшается не так резко, поскольку зависит от количества и сложности интерактивных элементов, а не только от способа рендеринга. Зато время до интерактивности обычно сокращается в 2-3 раза за счёт того, что гидратируется не вся страница целиком, а только реально интерактивные её части. Подробный разбор оптимизации именно этой метрики - в статье INP: метрика Core Web Vitals, которую все игнорируют.

Практический вывод - дело не в отказе от React

Вывод из всего вышесказанного не в том, что React непригоден для сайтов, которые должны хорошо ранжироваться. React-сайт на Next.js с SSR или SSG избегает большей части описанных проблем, а сайт в стиле обычного Create React App - нет, хотя оба технически написаны на одном фреймворке.

При выборе или аудите стека для сайта, который должен приносить органический трафик, стоит проверить четыре вещи:

  • Что реально приходит в ответе сервера до выполнения JS - пустой <div> или готовый контент. Проверяется через View Source в браузере или простым curl-запросом.
  • Какой режим рендеринга включён для страниц, которые должны индексироваться - CSR, SSR, SSG или ISR.
  • Сколько килобайт JavaScript грузится на странице без единой формы или калькулятора - через вкладку Coverage в DevTools.
  • Есть ли на сайте страницы, которые вообще не появляются в отчёте покрытия Google Search Console спустя недели после публикации.

Если сайт уже переписать полностью нельзя, частичная миграция критичных для SEO страниц - главной, страниц услуг, блога - на SSR или SSG обычно даёт основной прирост уже на первом этапе, без полной переработки всего продукта.

Для кого это критично

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

Также это критично для команд, которые уже мигрировали с WordPress или Tilda на современный стек, выбрали React ради гибкости, но не заметили, что выбранный шаблон проекта собирает чистый CSR SPA без единой настройки серверного рендеринга.

Часто задаваемые вопросы

Значит ли это, что от React нужно отказаться ради SEO?

Нет. Проблема не в React как библиотеке, а в режиме рендеринга. Next.js с SSR или SSG, а также React-компоненты внутри Astro-островов используют тот же React, но отдают браузеру и Googlebot готовый HTML в первом ответе сервера. Полностью клиентский рендеринг без единой серверной сборки - это выбор шаблона проекта, а не свойство самого React.

Помогает ли просто переход на SSR полностью решить проблему?

SSR решает основную часть проблемы с LCP, потому что контент приходит в первом HTML-ответе. INP решается им лишь частично: если после получения HTML браузеру всё равно нужно гидратировать большое дерево интерактивных компонентов, задержка отклика на клик остаётся. Для INP дополнительно помогает выборочная гидратация - Suspense-границы в React 18 или island-подход в Astro.

Может ли Googlebot вообще не проиндексировать SPA-сайт?

Полностью - редко, Google рендерит JavaScript уже несколько лет. Но рендеринг проходит вторым, отложенным этапом, и для страниц с низким приоритетом или больших сайтов с ограниченным краулинговым бюджетом эта задержка может растянуться на недели. За это время конкурент с готовым HTML в первом ответе уже проиндексирован и ранжируется.

В чём разница между SSR и SSG для SEO-эффекта?

SSG (Static Site Generation) собирает HTML заранее на этапе сборки, и сервер отдаёт готовый файл мгновенно - это быстрее всего для контента, который редко меняется: блог, страницы услуг, лендинги. SSR (Server-Side Rendering) собирает HTML на каждый запрос заново - подходит для страниц с персонализацией или часто меняющимися данными, но добавляет время ответа сервера по сравнению с уже готовым статическим файлом.

Что делать, если сайт уже на CSR SPA и полностью переписать его сейчас нельзя?

Частичная миграция обычно возможна: страницы, критичные для органического трафика - главная, услуги, блог - переносятся на SSR или SSG первыми, а продуктовая часть приложения может оставаться CSR SPA, потому что её не индексируют и на неё не заходят с холодного поиска. Это снижает объём работы и даёт эффект на самых важных для SEO страницах уже на первом этапе.

Итог

  • Сайт на React теряет позиции не из-за фреймворка, а из-за режима рендеринга - чистый клиентский рендеринг задерживает и LCP, и INP, и индексацию Googlebot.
  • Googlebot рендерит JavaScript в два прохода, и второй, отложенный проход может занять от часов до недель - контент, которого нет в исходном HTML, ждёт своей очереди.
  • Next.js с SSR/SSG и Astro с island-архитектурой решают проблему на уровне архитектуры, оставляя React как часть стека.
  • Частичная миграция критичных для SEO страниц на серверный или статический рендеринг обычно даёт основной прирост без переписывания всего продукта.

Если ваш сайт построен как чистый SPA на React и вы подозреваете, что это тормозит позиции в Google - опишите архитектуру команде Exceltic.dev. Разберём, что именно приходит в ответе сервера, и оценим объём работы для перехода на SSR или SSG.

Ещё статьи

Все →