AstroMiddleTechnical

Что такое 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.

Sources

Related topics

Что такое client-директивы в Astro (`client:load`, `client:idle`, `client:visible`, `client:only`)? В чём их различие? | Talanto