AstroMiddleTechnical

Как Astro поддерживает несколько UI-фреймворков (React, Vue, Svelte, Solid) одновременно?

Astro подключает каждый UI-фреймворк через отдельную интеграцию (@astrojs/react, @astrojs/vue и т.д.) в astro.config.mjs; компоненты разных фреймворков используются на одной странице, а директивы client:* контролируют когда и как они гидратируются.

Поддержка нескольких UI-фреймворков в Astro

Astro реализует концепцию «принеси свой фреймворк» (Bring Your Own Framework). Каждый фреймворк подключается через официальную интеграцию — пакет-адаптер, который учит Astro рендерить компоненты этого фреймворка. Несколько интеграций можно использовать одновременно.

Установка интеграций

# Через astro add (рекомендуется — автоматически правит astro.config.mjs)
npx astro add react vue svelte solid preact lit

# Вручную
npm install @astrojs/react react react-dom
npm install @astrojs/vue vue

Конфигурация

// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import vue from '@astrojs/vue';
import svelte from '@astrojs/svelte';
import solid from '@astrojs/solid-js';

export default defineConfig({
  integrations: [react(), vue(), svelte(), solid()],
});

Использование компонентов разных фреймворков

---
// src/pages/index.astro
import ReactCounter from '../components/Counter.tsx';    // React
import VueModal from '../components/Modal.vue';           // Vue
import SvelteTimer from '../components/Timer.svelte';     // Svelte
---

<ReactCounter client:load />
<VueModal client:visible />
<SvelteTimer client:idle />

Как это работает технически

Каждая интеграция регистрирует renderer — объект с методами check, renderToStaticMarkup и renderToString. Во время сборки Astro вызывает нужный renderer для серверного рендеринга (SSR/SSG). В браузере каждая интеграция добавляет маленький runtime — гидратационный код для своего фреймворка. React runtime, Vue runtime и Svelte runtime грузятся независимо и не конфликтуют.

Директивы client:* управляют гидратацией

  • client:load — гидратировать немедленно при загрузке страницы.
  • client:idle — гидратировать, когда браузер освободится (requestIdleCallback).
  • client:visible — гидратировать, когда элемент появится во viewport (IntersectionObserver).
  • client:media="(max-width: 768px)" — гидратировать при совпадении media query.
  • client:only="react" — пропустить серверный рендеринг, рендерить только в браузере.

Ограничения на вложенность

Компонент одного фреймворка не может рендерить компонент другого фреймворка как дочерний напрямую. Но можно вложить их через Astro-компонент-прослойку или передать HTML через слоты.

---
// НЕЛЬЗЯ: React-компонент не знает о Vue
import VueComp from './VueComp.vue';
// Внутри React-компонента нельзя использовать <VueComp />

// МОЖНО: вложенность через .astro
import ReactCard from './Card.tsx';
import VueTooltip from './Tooltip.vue';
---
<ReactCard client:load>
  <!-- slot-контент рендерится как статический HTML -->
  <VueTooltip client:visible />
</ReactCard>

Подводные камни

  • Раздутый бандл — каждый фреймворк добавляет свой runtime; если на одной странице React + Vue + Svelte, пользователь скачает три рантайма.
  • Конфликты при одном JSX-трансформере — Solid и React оба используют JSX; нужно настроить include/exclude в конфигурации каждой интеграции, чтобы они не перехватывали файлы друг друга.
  • client:only требует указания фреймворка — без аргумента (client:only без ="react") Astro не знает, какой runtime загрузить.
  • Общее состояние невозможно напрямую — React-компонент и Vue-компонент не могут использовать один React Context или Vue provide/inject; нужен Nano Stores или другое framework-агностичное решение.
  • HMR может ломаться — при одновременном использовании нескольких фреймворков горячая перезагрузка иногда требует полного обновления страницы.
  • SSR-только компоненты — без директивы client:* компонент рендерится только на сервере и не интерактивен; это нормально для статического контента, но легко забыть.
  • Версии peer-зависимостей — интеграция @astrojs/react 4.x требует React 18/19; смешивание несовместимых версий ломает сборку.

Common mistakes

  • Подключать несколько фреймворков без необходимости и платить рантаймами за каждый.
  • Ожидать, что React Context дойдёт до другого React-острова на той же странице.
  • Вкладывать гидрированный React в гидрированный Vue.

What the interviewer is testing

  • Знает про интеграции и их роль (renderer + client entrypoint).
  • Понимает ограничения совместного использования (нет общего контекста).
  • Аргументирует, когда смешивать стеки оправдано.

Sources

Related topics