Что такое client-директивы в Astro (client:load, client:idle, client:visible, client:only)? В чём их различие?
Client-директивы управляют моментом гидратации компонента: load — сразу, idle — в простое браузера, visible — при попадании в viewport, only — только на клиенте без SSR.
Client-директивы в Astro: управление гидратацией
По умолчанию Astro рендерит все компоненты на сервере и отправляет в браузер чистый HTML без JavaScript. Чтобы сделать UI-компонент (React, Vue, Svelte и т.д.) интерактивным на клиенте, нужно явно указать одну из client-директив. Без директивы компонент рендерится один раз на сервере и остаётся статичным.
client:load
Загружает и гидратирует компонент сразу при загрузке страницы. Это самый очевидный вариант, но и самый «дорогой» — JavaScript загружается немедленно, до того как пользователь вообще прокрутил страницу или нажал что-либо.
---
import Counter from '../components/Counter.jsx';
---
<Counter client:load />
Используйте для компонентов, которые должны быть интерактивны сразу: формы выше сгиба, главное меню с дропдаунами.
client:idle
Откладывает загрузку до момента, когда браузер перейдёт в состояние покоя — технически реализуется через requestIdleCallback (с fallback на setTimeout). Подходит для менее приоритетных виджетов: чаты поддержки, аналитические кнопки, счётчики просмотров.
---
import ChatWidget from '../components/ChatWidget.jsx';
---
<ChatWidget client:idle />
client:visible
Гидратирует компонент только когда он попадает в область видимости (viewport). Внутри используется IntersectionObserver. Идеален для длинных страниц, где блоки внизу могут вообще не увидеть большинство пользователей.
---
import Testimonials from '../components/Testimonials.jsx';
---
<!-- Гидратация произойдёт только при скролле до блока -->
<Testimonials client:visible />
Можно передать порог видимости через объект: client:visible={{ rootMargin: "200px" }} — это инициирует загрузку за 200px до появления элемента.
client:only
Полностью пропускает серверный рендеринг — компонент существует только на клиенте. Необходимо явно указать фреймворк строкой. Применяется когда компонент использует browser-only API (window, localStorage, WebGL) или сторонние библиотеки, которые не поддерживают SSR.
---
import MapComponent from '../components/Map.jsx';
---
<!-- Фреймворк указывается явно, SSR полностью отключён -->
<MapComponent client:only="react" />
client:media
Гидратирует компонент только если совпадает CSS media query. Удобно для мобильных меню, которые не нужны на десктопе.
<MobileMenu client:media="(max-width: 768px)" />
Сравнительная таблица
- client:load — немедленно при загрузке страницы; наивысший приоритет
- client:idle — когда браузер не занят (
requestIdleCallback) - client:visible — когда элемент попадает в viewport (
IntersectionObserver) - client:only="framework" — только на клиенте, серверный рендеринг полностью отключён
- client:media — только при совпадении media query
Подводные камни
- client:only без указания фреймворка вызовет ошибку сборки — строка вроде
"react"обязательна. - client:load для всего уничтожает преимущество Astro — вы получаете SPA без его удобств. Директиву стоит использовать осознанно.
- client:visible и rootMargin: по умолчанию threshold равен 0, компонент загрузится только когда хотя бы 1 пиксель попадёт в viewport. На медленных соединениях это может привести к заметной задержке гидратации.
- Отсутствие SSR при client:only: поисковые роботы не увидят контент такого компонента. Не используйте для SEO-критичного текста.
- Вложенные компоненты: если родительский Astro-компонент имеет
client:load, дочерние framework-компоненты гидратируются автоматически в рамках своего фреймворка — дополнительные директивы на дочерних не нужны. - requestIdleCallback отсутствует в Safari до версии 16.4. Astro использует fallback, но это означает что
client:idleв старых Safari ведёт себя какclient:load. - Несколько фреймворков на одной странице: каждый бандл загружается отдельно. Смешивание React и Vue увеличивает общий размер JS.
- Props при client:only: props сериализуются в HTML-атрибут и отправляются на клиент — не передавайте чувствительные данные.
Common mistakes
- Ставить
client:loadбез необходимости и платить трафиком. - Использовать
client:onlyдля компонентов, которые могли бы серверно отрендериться. - Передавать в пропсы функции или объекты с методами — они теряются при сериализации.
What the interviewer is testing
- Различает все пять директив и приводит сценарии для каждой.
- Понимает, что props сериализуются в JSON.
- Видит влияние директив на TTI и SEO.