Как работает динамический рендеринг для JS-сайтов. Настройка prerender для Яндекса, решение проблем с индексацией SPA и AJAX-контента. Пошаговое руководство по внедрению серверного рендеринга для поисковых ботов.
Введение
Вы потратили полгода на разработку современного сайта на React или Vue. Дизайн великолепен, интерфейс летает, пользователи в восторге. Но проходит месяц после запуска, а трафик из Яндекса — кот наплакал. Заходите в Вебмастер и видите: страницы в индексе есть, но все сниппеты пустые, тексты не читаются, ключевые слова не определяются. Знакомая боль? Корень проблемы в том, что ваш контент генерируется на стороне клиента через JavaScript, а робот Яндекса, хоть и научился исполнять JS, делает это с задержкой и ограничениями. Решение существует — динамический рендеринг. Это технология, при которой обычным пользователям отдаётся JS-версия сайта, а поисковым ботам — заранее подготовленный статический HTML. В этой статье мы разберём, как работает динамический рендеринг, кому он реально нужен, как его настроить для Яндекса и каких ошибок избежать при внедрении.
Почему JavaScript — проблема для индексации
Представьте, что вы даёте человеку книгу, но все страницы в ней пустые, а текст появляется только после того, как он произнесёт специальное заклинание. Примерно так поисковый робот видит JS-сайт. Робот Яндекса скачивает HTML-файл, а в нём — только пустой контейнер и ссылки на JavaScript-файлы. Чтобы увидеть контент, роботу нужно скачать эти файлы, выполнить их, дождаться ответа от API и отрисовать страницу — на всё это уходит время и ресурсы. Яндекс заявляет, что его робот умеет исполнять JavaScript, и это правда. Но есть нюансы. Во-первых, JS-рендеринг происходит не одновременно с первым обходом, а с задержкой — иногда в несколько дней или даже недель. Во-вторых, робот не бесконечно терпелив: если скрипт выполняется дольше определённого таймаута, страница попадёт в индекс в том виде, в каком робот её застал — то есть пустой. В-третьих, некоторые современные фичи JavaScript робот просто не поддерживает. Например, динамические импорты, WebSocket-соединения или обращение к локальному хранилищу браузера могут отрабатывать некорректно или не отрабатывать вовсе. Результат: контент, который видят пользователи, и контент, который видит робот — две разные вселенные. Более подробно о том, как отследить поведение робота на сайте, мы рассказывали в статье Как читать логи сервера для SEO-аудита — там описаны методы анализа access-логов для выявления проблем с обходом.
Что такое динамический рендеринг простыми словами
Динамический рендеринг — это компромисс между современной frontend-разработкой и требованиями поисковых систем. Суть проста: на сервере стоит прослойка, которая определяет, кто именно запрашивает страницу — человек или бот. Если пришёл обычный посетитель с браузером — ему отдаётся обычная JS-версия сайта, всё как обычно. Если пришёл бот Яндекса (или Google, или любой другой) — ему отдаётся заранее сгенерированная статическая HTML-копия этой же страницы. Эта копия содержит весь текст, все мета-теги, все ссылки — всё, что нужно для индексации, но без необходимости исполнять JavaScript. Генерацией таких копий занимается отдельный сервис — prerender-сервер. Он берёт ваш JS-сайт, запускает его в headless-браузере (браузере без графического интерфейса), дожидается полной отрисовки, сохраняет получившийся HTML и отдаёт его боту. Для бота это выглядит как обычный статический сайт — быстро, надёжно, без сюрпризов. Для пользователя ничего не меняется — он по-прежнему получает интерактивное JS-приложение.
Кому нужен динамический рендеринг, а кому нет
Динамический рендеринг — не серебряная пуля и нужен не всем. Если ваш сайт — это блог на WordPress с парой анимаций на jQuery, вам это не нужно. Робот Яндекса прекрасно индексирует такой контент без дополнительных ухищрений. Если у вас интернет-магазин, где каталог генерируется на сервере, а JS используется только для корзины и фильтров — тоже мимо. Динамический рендеринг нужен в трёх случаях. Первый: SPA-приложения на React, Vue, Angular, где весь HTML состоит из одной строчки и тега с атрибутом id="app". Второй: сайты, где контент подгружается асинхронно через AJAX-запросы — например, бесконечная лента новостей или товары, подгружаемые по кнопке «Показать ещё». Третий: сайты, где критически важный контент (цены, описания, контакты) формируется динамически на основе геолокации или авторизации пользователя. В этих случаях без динамического рендеринга вы рискуете, что робот просто не увидит ваш контент и не проиндексирует его.
Как настроить динамический рендеринг: три способа
Способ первый — готовые облачные сервисы. Самый простой для старта. На рынке есть несколько решений, которые работают по принципу «подключил и забыл». Вы регистрируетесь в сервисе, прописываете ваш домен, и сервис начинает кешировать prerender-копии ваших страниц. Когда приходит бот, он перенаправляется на сервис, а тот отдаёт готовый HTML. Плюсы: настройка за 15 минут, не требует серверных мощностей. Минусы: ежемесячная плата, зависимость от стороннего сервиса. Способ второй — свой prerender-сервер. Это когда вы поднимаете отдельный сервер (или контейнер), на котором крутится Chromium в headless-режиме и генератор статических копий. Популярное решение — Puppeteer, библиотека от Google для управления headless-браузером. На VPS от российского хостера разворачиваете Node.js, ставите Puppeteer, пишете скрипт, который принимает URL на вход и возвращает отрендеренный HTML на выходе. Затем настраиваете nginx так, чтобы запросы от ботов проксировались на этот prerender-сервер. Плюсы: полный контроль, нет ежемесячной платы. Минусы: требует компетенций в DevOps, свой сервер нужно поддерживать и мониторить.
Настройка nginx для определения ботов
Ключевой момент динамического рендеринга — правильно определить, кто стучится к серверу. В nginx это делается через анализ User-Agent. Создаём в конфиге карту user-agent-ов поисковых ботов: YandexBot, YandexMobileBot, Googlebot, Mail.RU_Bot и других. Если User-Agent совпадает с одним из них, запрос направляется на prerender-сервер. Важный нюанс: Яндекс использует разные User-Agent для разных типов обхода. Основной поисковый бот — YandexBot. Но есть ещё YandexMobileBot для мобильного индекса, YandexImage для картинок, YandexVideo для видео. Если вы настраиваете динамический рендеринг, нужно охватить как минимум основного бота и мобильного. Отдельная история — проверка подлинности бота. Как мы говорили в статье про анализ логов, User-Agent можно подделать. Чтобы какой-нибудь парсер не заставил ваш prerender-сервер генерировать копии впустую, добавьте проверку по IP. Список диапазонов IP Яндекса публикуется в официальной справке. Настройте nginx так, чтобы prerender включался только при совпадении и User-Agent, и IP-адреса с диапазонами Яндекса. Это чуть сложнее, но убережёт от паразитной нагрузки.
Типичные ошибки при внедрении динамического рендеринга
Ошибка первая: рассинхрон контента. Самое страшное, что может случиться — бот получает одну версию страницы, а пользователь другую. Например, на prerender-копии цена товара 1000 рублей, а в реальном JS-приложении она обновляется каждые 5 минут и уже 1200 рублей. Это классический клоакинг, за который поисковые системы банят. Решение: кеш prerender-копий должен инвалидироваться при каждом изменении данных. Либо время жизни кеша должно быть минимальным — 5-10 минут для динамических страниц. Ошибка вторая: потеря интерактивных элементов в prerender-версии. Если ваш сайт использует сложную навигацию с выпадающими меню, фильтрами и сортировками, убедитесь, что в статической HTML-копии есть обычные ссылки на все важные страницы. Бот не будет кликать по кнопкам, он идёт по ссылкам. Если все ссылки на товары спрятаны за JavaScript-обработчиками, бот их не найдёт ни в JS-версии, ни в prerender-копии. Ошибка третья: неполная отрисовка. Headless-браузер, который генерирует prerender-копию, должен ждать полной загрузки страницы. Если скрипт прерывает ожидание слишком рано, в копию попадёт полупустая страница с крутящимся спиннером. Настройте ожидание не по времени, а по появлению ключевых элементов на странице — например, дождитесь появления блока с ценой или текстом статьи.
Проверка, что динамический рендеринг работает
После настройки обязательно проверьте результат. Способ первый: инструмент «Проверить URL» в Яндекс.Вебмастере. Вставьте адрес страницы и посмотрите, какой HTML видит бот. Там должен быть весь контент — текст, ссылки, мета-теги. Если вместо контента вы видите пустой div или спиннер загрузки — prerender не сработал. Подробно о работе с этим и другими инструментами Вебмастера читайте в статье Яндекс.Вебмастер для индексации: полный обзор инструментов. Способ второй: curl с подменой User-Agent. Откройте консоль на сервере и выполните запрос к своему сайту, указав User-Agent Яндекса. В ответе вы должны получить полный HTML с текстом, а не пустую оболочку. Сравните этот вывод с обычным запросом без подмены User-Agent — разница должна быть очевидна. Способ третий: Яндекс.Метрика. Если у вас настроена передача данных о загрузке страницы в Метрику, вы увидите, как изменилось время загрузки для ботов после внедрения динамического рендеринга.
Альтернативы динамическому рендерингу
Динамический рендеринг — не единственный способ подружить JS-сайт с поисковиками. Рассмотрим альтернативы. Первая: серверный рендеринг. Современные фреймворки — Next.js для React, Nuxt.js для Vue — умеют генерировать HTML на сервере сразу, без дополнительных прослоек. Это более правильный с архитектурной точки зрения подход: сервер отдаёт готовую страницу и пользователю, и боту. Если вы только начинаете проект на JS-фреймворке, выбирайте фреймворк с серверным рендерингом из коробки. Вторая альтернатива: статическая генерация. Если контент сайта не меняется в реальном времени, можно генерировать статические HTML-файлы при каждой публикации и отдавать их всем. Третья: гибридный подход. Критически важные для SEO страницы (каталог, карточки товаров) отдаются с серверным рендерингом, а личный кабинет, корзина и прочие интерактивные разделы — как SPA. Такой подход даёт максимальную скорость индексации там, где это нужно, и сохраняет интерактивность там, где это важно пользователю.
Часто задаваемые вопросы
Яндекс ведь умеет исполнять JavaScript, зачем мне динамический рендеринг? Умеет, но с задержкой. JS-рендеринг происходит не при первом обходе, а во вторую волну, которая может отставать на дни и недели. Если ваш контент часто обновляется, вы будете постоянно опаздывать. Динамический рендеринг гарантирует, что бот получит контент сразу при первом обходе.
Не попадёт ли сайт под фильтр за клоакинг? Не попадёт, если контент prerender-копии полностью совпадает с тем, что видит пользователь. Клоакинг — это показ разного контента людям и ботам с целью манипуляции ранжированием. Динамический рендеринг решает техническую проблему доступности контента, а не подменяет его. Главное — следить за идентичностью текстов, цен, наличия товаров.
Можно ли использовать динамический рендеринг только для Яндекса? Можно, но нет смысла ограничиваться одним поисковиком. Настройте список User-Agent так, чтобы prerender-копии получали все крупные поисковые системы: Яндекс, Google, Mail.ru. Для социальных сетей (ВКонтакте, Одноклассники) тоже полезно — они используют свои боты для генерации превью ссылок.
Сколько стоит внедрение динамического рендеринга? Если делать своими силами на своём VPS — стоимость ограничивается арендой дополнительного сервера или контейнера, примерно от 800 до 2000 рублей в месяц у российских провайдеров. Готовые облачные сервисы стоят от 3000 рублей в месяц за сайт среднего размера. Разработка кастомного решения силами подрядчика — от 50 000 до 150 000 рублей единоразово.
Как часто нужно обновлять prerender-кеш? Зависит от динамики контента. Для новостного сайта — каждые 5-10 минут. Для каталога товаров, где цены меняются раз в день — раз в сутки. Для блога со статьями — можно кешировать до следующего обновления статьи. Настройте инвалидацию кеша по событиям: изменилась статья — сбрасываем кеш этой страницы.