SEO

SEO для сайтов на React и Next.js: что важно

«React плох для SEO» — один из самых живучих мифов веб-разработки. Доля правды в нём есть, но относится она к одному конкретному способу использовать React, а не к самому React.

Если у вас сайт на React или Next.js или вы только выбираете технологию, по сути вопросов два. Видит ли поисковик содержимое страницы, не запуская JavaScript? И в порядке ли сайт технически, как любой другой хорошо сделанный сайт? Первое — вопрос архитектуры, второе — вопрос чек-листа.

Откуда взялся миф

Классическое React-приложение (SPA, single-page application) отдаёт с сервера почти пустой HTML: один <div> и ссылку на файл скрипта. Всё содержимое — заголовки, тексты, ссылки — появляется только после того, как браузер скачал и выполнил JavaScript.

Человеку всё равно: он видит готовую страницу. Поисковому роботу — нет.

Google умеет рендерить JavaScript, но на отдельном этапе. Сначала он читает HTML, а рендеринг происходит позже, когда до него доходят ресурсы. Обычно это срабатывает. Но если скрипт падает с ошибкой, запрос данных не укладывается во время или какой-то файл закрыт в robots.txt, Google проиндексирует то, что было в HTML, — то есть ничего.

Многие другие не рендерят вовсе. Большинство других краулеров, роботы ИИ-сервисов и превью ссылок (Facebook, LinkedIn, Slack, WhatsApp) читают только исходный HTML. Для них страница, отрисованная на клиенте, пуста: у отправленной ссылки нет заголовка и картинки, а ИИ-поиску нечего цитировать.

Значит, проблема не в React, а в том, где собирается HTML.

Решение: HTML собирается на сервере или при сборке

Два способа, и оба сразу отдают роботу готовое содержимое:

  • Серверный рендеринг (SSR) — сервер собирает HTML на каждый запрос.
  • Статическая генерация (SSG) — HTML собирается заранее, во время сборки (build), а сервер просто отдаёт готовый файл.

Next.js делает это по умолчанию. В App Router компоненты по умолчанию серверные, а страница генерируется статически, если ей не нужны данные конкретного запроса. Каждый URL возвращает настоящий HTML с содержимым; JavaScript лишь добавляет поверх интерактивность (это называется гидратацией).

Быстрая проверка: есть ли текст в HTML?

Откройте страницу, нажмите Ctrl+U (на Mac Cmd+Option+U) и найдите на ней какую-нибудь фразу. Не через инструменты разработчика — они показывают страницу уже после выполнения JavaScript. То же из командной строки:

curl -s https://vash-sayt.ee/uslugi/ | grep -c "фраза, которая видна на странице"

Если результат 0, содержимое появляется только в браузере. Инструмент проверки URL в Search Console дополнительно показывает, какой HTML получил Google после рендеринга.

Чек-лист для сайта на React и Next.js

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

Свой title и meta description на каждой странице. Самая частая ошибка SPA — один и тот же заголовок на всех URL. В Next.js его задаёт экспорт metadata, а на динамических страницах — generateMetadata, и он попадает в <head> уже на сервере, а не позже.

Canonical. Каждая страница сообщает, какой URL — её официальный адрес. Иначе варианты с параметрами запроса или со слешем в конце могут конкурировать как дубли одной страницы.

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

Генерируемые sitemap.xml и robots.txt. В Next.js это файлы app/sitemap.ts и app/robots.ts. Карта сайта строится из тех же данных, что и страницы, поэтому новую страницу в ней невозможно забыть. Наш сайт генерирует sitemap во время сборки.

Структурированные данные (JSON-LD). Компания, услуги, статьи, FAQ и хлебные крошки в блоке <script type="application/ld+json">. Он должен быть в исходном HTML, а не добавляться позже на клиенте.

Настоящие ссылки. Google переходит по ссылкам <a href>, по кнопкам он не кликает. Компонент Link в Next.js отрисовывает нормальный элемент <a>. Навигация, которая работает только через onClick и router.push(), для робота невидима.

Настоящий 404. Отсутствующая страница должна отдавать HTTP-код 404, а не 200 с текстом «страница не найдена» — второе Google называет мягкой ошибкой 404 (soft 404). В Next.js за это отвечает notFound(). При статическом экспорте хостинг должен отдавать страницу 404 с правильным кодом.

Одно правило для слеша в конце. /uslugi и /uslugi/ — два разных URL. Выберите один вариант (trailingSlash в Next.js), второй перенаправьте 301-м редиректом и следите, чтобы внутренние ссылки использовали ту же форму. Если новый сайт заменяет старый, посмотрите также, как сделать редизайн сайта без потери SEO.

Изображения с размерами и alt-текстом. width и height заранее резервируют место, и содержимое не прыгает (CLS). next/image всё равно их требует. При статическом экспорте автоматическая оптимизация изображений в Next.js отключена — картинки нужно заранее сжать до разумного размера.

Клиентские компоненты — только там, где есть взаимодействие. 'use client' отправляет компонент в браузер вместе со всем, что он импортирует. Меню, форме и фильтру это нужно; текстовому блоку и подвалу — нет.

Скорость: ловушки, характерные для React

Общая картина Core Web Vitals разобрана в статье скорость сайта: как её измерить и улучшить. У сайта на React сверх этого есть три собственные ловушки.

Объём JavaScript и гидратация

Даже страница, отрисованная на сервере, скачивает JavaScript и гидратируется. Пока это не закончилось, кнопки не реагируют — это бьёт по INP, особенно на недорогих телефонах. Каждый клиентский компонент и каждая библиотека (карусель, библиотека анимаций, библиотека для работы с датами) увеличивают бандл. Тяжёлый виджет внизу страницы стоит загружать только тогда, когда он нужен (next/dynamic).

Не прячьте заголовок за JavaScript

Распространённый приём: содержимое плавно «проявляется», а для этого изначально стоит opacity: 0, пока скрипт не разрешит его показать. Если так поступить с главным заголовком страницы, LCP — главный показатель скорости загрузки у Google — будет ждать, пока скачается JavaScript и пройдёт гидратация. А если скрипт не загрузится, заголовок так и останется невидимым.

Мы усвоили это на собственном сайте. Заголовок главной страницы — LCP-элемент, и теперь у него чистая CSS-анимация, которая стартует с первой отрисовки, а не появление по команде JavaScript. Эффекты при прокрутке ниже по странице — отдельная история, заголовок от них не зависит.

Не отправляйте в браузер все языки

На многоязычном сайте легко случайно импортировать в клиентский компонент весь словарь переводов. Тогда каждый посетитель скачивает тексты на всех языках. Правильнее так: серверный компонент читает текст и передаёт клиентскому через props только нужные ему строки.

Статический экспорт: каждая страница — готовый файл

Next.js умеет экспортировать весь сайт в чистый HTML (output: 'export'). На выходе — папка файлов, которую отдаст любой веб-сервер или CDN.

  • Быстро — в момент посещения сервер ничего не вычисляет.
  • Безопасно — нет базы данных, админки и серверного кода, которые можно атаковать.
  • Дёшево в размещении — хватает обычного статического хостинга.

Наш собственный сайт — полностью статический экспорт: Next.js (App Router), React и TypeScript, пять языков.

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

Если вы сейчас на WordPress и думаете о переезде, прочитайте переход с WordPress без потери SEO и более общее сравнение WordPress или сайт на коде.

Когда звать на помощь

Если у вас уже есть сайт на React, сделайте три проверки: посмотрите исходный код трёх страниц, сравните число проиндексированных страниц в Search Console с реальным числом страниц и проверьте, отличаются ли заголовки от страницы к странице. Если текста нет в HTML, правка метатегов не поможет — нужно перестраивать рендеринг, часто с переходом с SPA на Next.js.

Мы делаем сайты на Next.js так, чтобы всё перечисленное было заложено с самого начала. Если сайт уже есть, но в Google не двигается, начните с SEO-продвижения.

Читайте также

Связанные услуги

Готовы вывести свой бизнес на новый уровень?

Свяжитесь с нами сегодня — и сделаем вместе что-то выдающееся.

Связаться с нами