Согласие на cookie для Next.js, Gatsby и статических сайтов: руководство по интеграции для разработчиков

Проблема согласия на статических сайтах

Современные JavaScript-фреймворки, такие как Next.js, Gatsby и Nuxt.js, привнесли смену парадигмы в способ создания и доставки веб-страниц. Страницы предварительно рендерятся во время сборки или на сервере, а затем гидратируются на клиенте. Это создаёт уникальную проблему для согласия на cookie: баннер согласия должен быть готов до выполнения любых скриптов отслеживания, но сама страница может быть уже отрендерена и закэширована на границе сети.

Традиционные CMP были разработаны для серверно рендеримых PHP или простых HTML-страниц, где документ загружается линейно сверху вниз. В мире фреймворков с разделением кода, ленивой загрузкой и потоковым серверным рендерингом эти предположения нарушаются. Чтобы правильно настроить согласие в этих средах, нужно понимать конвейер рендеринга.

Почему тайминг важнее, чем вы думаете

На стандартной HTML-странице размещение скрипта CMP в <head> перед другими скриптами просто. В Next.js App Router или Gatsby ситуация сложнее:

Основной принцип таков: согласие должно устанавливаться на уровне скрипта, а не на уровне компонента. Компонент React, который рендерит баннер согласия, слишком запаздывает, если становится интерактивным только после гидратации.

Интеграция с Next.js App Router

Next.js 13+ с App Router привнёс новый способ обработки скриптов. Вот рекомендуемый подход для интеграции согласия:

Шаг 1: загрузите скрипт CMP в корневом макете

Используйте компонент Next.js Script со стратегией beforeInteractive в вашем корневом layout.tsx. Это указывает Next.js внедрить скрипт в исходный HTML-документ до начала гидратации:

Стратегия beforeInteractive критически важна. Стратегия по умолчанию afterInteractive загружает скрипты после гидратации, что слишком поздно для согласия. При beforeInteractive скрипт CMP включается в серверно рендеримый HTML и выполняется при загрузке страницы.

Шаг 2: установите согласие по умолчанию перед тегами Google

Перед вашим сниппетом Google Tag Manager или gtag.js включите инлайн-скрипт, который устанавливает состояния согласия по умолчанию. Это гарантирует, что даже если GTM загрузится до появления баннера CMP, он будет уважать настройки отказа по умолчанию:

Этот инлайн-скрипт следует разместить в <head> вашего корневого макета, перед скриптами CMP и GTM. В Next.js для этой цели вы можете использовать обычный тег <script> внутри элемента <head> вашего макета.

Шаг 3: обрабатывайте изменения маршрута

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

Интеграция с Next.js Pages Router

Для проектов, всё ещё использующих Pages Router, подход аналогичен, но использует _document.tsx вместо корневого макета. Разместите скрипт CMP в компоненте <Head> вашего пользовательского класса Document. Стратегия beforeInteractive работает таким же образом в Pages Router.

Ключевое отличие в том, что _document.tsx рендерится только на сервере, поэтому любая логика согласия здесь гарантированно находится в исходной полезной нагрузке HTML.

Интеграция со статическим сайтом Gatsby

Gatsby генерирует полностью статический HTML во время сборки. Серверного рендеринга во время запроса нет, что упрощает одни аспекты, но усложняет другие:

Подход Gatsby на основе времени сборки означает, что каждый HTML-файл на вашем CDN будет включать скрипт согласия. Это на самом деле идеально — нет серверной логики, которая может дать сбой или неправильно закэшироваться.

Соображения по Nuxt.js

Nuxt.js (на основе Vue) имеет свои собственные паттерны. В Nuxt 3 используйте composable useHead или конфигурацию app head в nuxt.config.ts, чтобы добавить скрипт CMP глобально. Nuxt поддерживает опцию body: false (которая размещает скрипты в head) и атрибут async для неблокирующей загрузки.

Для режима серверного рендеринга Nuxt применяется тот же принцип: скрипт CMP должен быть в исходном HTML-ответе, а не динамически внедряться компонентом Vue после монтирования.

Избегание сдвига макета

Баннеры согласия печально известны тем, что вызывают Cumulative Layout Shift (CLS) — Core Web Vital, влияющий на SEO-рейтинги. Когда баннер всплывает после рендеринга страницы, он сдвигает контент вниз или неожиданно накладывается на него.

Стратегии минимизации CLS от баннеров согласия:

Фреймворк-независимый подход FlexyConsent

FlexyConsent был разработан для работы с любым фреймворком — или вообще без фреймворка — за счёт работы на уровне скрипта, а не на уровне компонента. Вот почему это важно:

Совет разработчику: самый простой тест правильной интеграции CMP — открыть вкладку Network в браузере, отфильтровать по доменам Google и перезагрузить страницу. Никакие запросы Google не должны срабатывать до появления команды согласия по умолчанию в консоли. Если они срабатывают, ваша CMP загружается слишком поздно.

Бесплатный план FlexyConsent поддерживает неограниченные просмотры страниц и работает с Next.js, Gatsby, Nuxt, Astro, SvelteKit, Remix и обычным HTML. Интеграция одинакова для всех них: один тег скрипта, правильно размещённый.

← Блог Читать все →