Przejdź do treści

Zarządzanie starszymi architekturami: jak łączyć React, Svelte i Vue w jednym projekcie Astro

Opublikowano
28 maja 2026
Aktualizacja
1 lipca 2026
Czas czytania
12 min czytania

Architektura wysp jako warstwa, nie framework

Najpierw trzeba przestawić sobie jedną rzecz w głowie: Astro nie jest konkurentem dla React, Vue czy Svelte i niczego nie zastępuje. To warstwa architektoniczna, która decyduje, jak i kiedy kod tych frameworków trafia do klienta.

Astro renderuje stronę domyślnie jako HTML i CSS, zerując client-side JavaScript. Tam, gdzie potrzebujesz interaktywności, umieszczasz — komponent konkretnego frameworka, który niezależnie. Ponieważ wyspy są od siebie odseparowane, możesz mieszać kilka frameworków na jednej stronie: React obsługuje wyszukiwarkę, Vue zasila widżet onboardingu, Svelte renderuje lekki licznik. Każda wyspa płaci tylko za swój własny JavaScript.

To właśnie ta niezależność czyni Astro idealnym narzędziem do migracji: pozwala inkrementalnie konwertować istniejącą witrynę na inny framework bez downtime’u.

Kiedy Astro ma sens jako warstwa migracyjna

Astro nie naprawia każdej starszej aplikacji frontendowej, działa najlepiej wtedy, gdy publiczna część systemu jest w dużej mierze treściowa, ale w środku ma kilka ciężkich, interaktywnych fragmentów. Może to być strona landingowa,wyszukiwarka, konfigurator, kalkulator, panel porównania, mapa, formularz wieloetapowy albo widget użytkownika.

W takim projekcie nie musisz przenosić całego frontendu do jednego nowego frameworka. Możesz potraktować Astro jako warstwę kompozycji: statyczne sekcje lądują w .astro, stary React działa jako wyspa, nowy moduł powstaje w Svelte, a istniejący komponent Vue zostaje tam, gdzie już spełnia swoje zadanie.

To podejście ma sens szczególnie wtedy, gdy:

  • część strony musi zostać stabilna, bo obsługuje sprzedaż, leady albo ruch SEO,
  • zespół nie ma budżetu na jednorazowe przepisanie całego systemu,
  • kilka modułów pochodzi z różnych epok technologicznych,
  • nowy kod chcesz pisać inaczej, ale bez zatrzymywania starego,
  • największy koszt wydajnościowy siedzi w kilku konkretnych panelach, nie w całym systemie.

Jeśli jednak cały produkt jest jedną aplikacją z intensywnym stanem, sesją użytkownika, panelem administracyjnym, routingiem aplikacyjnym i zależnościami między ekranami, Astro może być złym narzędziem na rdzeń. Wtedy lepiej rozważyć jeden framework aplikacyjny, a Astro zostawić dla marketingu, dokumentacji albo bloga.

Audyt legacy przed migracją

Najczęstszy błąd to zacząć od pytania „React, Vue czy Svelte?”. W starszej architekturze ważniejsze jest pytanie: które fragmenty systemu można bezpiecznie odizolować?

Przed pierwszą migracją rozpisz moduły w prostej tabeli:

ModułObecny frameworkStanRoutingCSSRyzykoDecyzja
Hero i sekcje ofertoweReactbrakbrakglobalny CSSniskieprzenieść do .astro
Wyszukiwarka produktówReactlokalny stan + APIquery paramsCSS Modulesśredniewyspa React, potem refaktor
Konfigurator cenyVuedużo stanubrakscoped styleswysokiezostawić jako wyspę
Nowy kalkulator ROIbraklokalny stanbraknowy design systemniskiezbudować w Svelte

To ćwiczenie wymusza decyzje techniczne bez zgadywania. Moduł statyczny nie powinien dalej żyć w Reactcie tylko dlatego, że tak powstał pięć lat temu. Moduł krytyczny, który działa i ma wiele edge case’ów, nie musi być przepisywany pierwszy tylko dlatego, że wygląda „staro”.

W praktyce szukasz trzech typów fragmentów:

  • statyczne — treść, layout, sekcje marketingowe, FAQ, tabele, opisy; najlepszy kandydat do .astro,
  • izolowane interakcje — formularz, filtr, kalkulator, galeria; dobry kandydat na wyspę,
  • aplikacyjne moduły — dashboard, edytor, koszyk, panel użytkownika; zostaw ostrożnie albo trzymaj poza Astro, jeśli zależności są zbyt silne.

Konfiguracja: trzy frameworki obok siebie

Technicznie to zaskakująco proste. Instalujesz oficjalne integracje i deklarujesz je w konfiguracji:

Code
// astro.config.mjs
import { defineConfig } from 'astro/config'
import react from '@astrojs/react'
import vue from '@astrojs/vue'
import svelte from '@astrojs/svelte'
 
export default defineConfig({
  // Kilka integracji naraz — to w pełni wspierany scenariusz.
  integrations: [react(), vue(), svelte()],
})

Astro oficjalnie wspiera React, Preact, Svelte, Vue, SolidJS i AlpineJS, a społeczność dorzuca kolejne (Angular, Qwik). Komponenty trzymasz po prostu w odpowiednich rozszerzeniach, czyli .jsx/.tsx dla Reacta, .vue dla Vue, .svelte dla Svelte, a potem je importujesz do strony Astro:

Code
---
// src/pages/dashboard.astro
import LegacySearch from '../components/LegacySearch.jsx';   // stary React
import NewFilters from '../components/NewFilters.svelte';    // nowy Svelte
import OnboardingWidget from '../components/Onboarding.vue'; // istniejący Vue
---
 
<main>
  <LegacySearch client:load />
  <NewFilters client:visible />
  <OnboardingWidget client:idle />
</main>

Jedna ważna granica: plik komponentu danego frameworka nie może mieszać frameworków w środku. Nie wstawisz Vue do wnętrza komponentu React. Mieszanie odbywa się na poziomie strony Astro, która jest rodzicem renderującym wyspy. To pozwala budować całe „aplikacje” w wybranym frameworku i osadzać je przez komponent-rodzic.

Dyrektywy client: — kontrola kosztu hydratacji

Sekret wydajnej migracji leży w dyrektywach hydratacji. To one decydują, kiedy dana wyspa pobiera i uruchamia swój JavaScript:

  • client:load — hydratacja natychmiast po załadowaniu strony. Dla elementów krytycznych, widocznych od razu.
  • client:idle — gdy przeglądarka skończy pilniejsze zadania. Dla elementów ważnych, ale nie pilnych.
  • client:visible — dopiero gdy element wejdzie w viewport. Idealne dla ciężkich, starych paneli niżej na stronie — nie płacisz za ich JS, dopóki użytkownik do nich nie dotrze.
  • client:only — pomija render po stronie serwera; wyspa istnieje wyłącznie w kliencie (musisz podać framework, np. client:only="react").

W migracji legacy client:visible pozwala zostawić stary, ciężki panel React na stronie, ale odłożyć jego hydratację do momentu, w którym użytkownik faktycznie do niego dociera. Dzięki temu reszta strony może załadować się szybciej, bez płacenia kosztu JavaScriptu za moduł, którego jeszcze nie widać.

Wielka migracja nie wymaga wielkiego ryzyka. Wymaga architektury, która pozwala wymieniać panele po jednym, podczas gdy produkcja dalej zarabia.

Strategia migracji: jak odciążać stare panele

Teraz złóżmy to w plan działania, który nie przerywa dostaw na produkcję.

Krok 1: opakuj istniejącą aplikację jako wyspę

Zamiast przepisywać, najpierw przenieś istniejący panel (np. cały moduł React) do Astro jako pojedynczą wyspę client:only="react". Strona ładuje się jak dotąd, ale od teraz żyje w środowisku Astro. Zero zmian w logice, zero downtime’u. To Twój bezpieczny punkt wyjścia.

W realnym projekcie „opakowanie” rzadko oznacza samo przeniesienie pliku. Często musisz odtworzyć minimalny zestaw zależności starego modułu:

  • providery Reacta, Vue pluginy albo Svelte store’y,
  • klienta API i konfigurację środowisk,
  • globalne style, reset CSS albo style biblioteki komponentów,
  • tłumaczenia i formatowanie dat/liczb,
  • analitykę zdarzeń, jeśli moduł wysyła eventy do GA4, Segmenta albo własnego backendu,
  • placeholder, jeśli używasz client:only i komponent nie renderuje HTML na serwerze.

Dobrym wzorcem jest cienki adapter:

Code
// components/legacy/LegacySearchIsland.tsx
import { LegacySearch } from './LegacySearch'
import { LegacyApiProvider } from './legacy-api'
import { LegacyI18nProvider } from './legacy-i18n'
 
type LegacySearchIslandProps = {
  apiBaseUrl: string
  initialQuery?: string
}
 
export function LegacySearchIsland(props: LegacySearchIslandProps) {
  return (
    <LegacyApiProvider baseUrl={props.apiBaseUrl}>
      <LegacyI18nProvider locale="pl">
        <LegacySearch initialQuery={props.initialQuery ?? ''} />
      </LegacyI18nProvider>
    </LegacyApiProvider>
  )
}
Code
---
import { LegacySearchIsland } from '../components/legacy/LegacySearchIsland'
---
 
<LegacySearchIsland
  client:visible
  apiBaseUrl={import.meta.env.PUBLIC_API_URL}
  initialQuery={Astro.url.searchParams.get('q') ?? ''}
/>

Adapter jest miejscem, w którym zamykasz brzydkie zależności starego świata. Reszta strony Astro nie musi wiedzieć, jak działa dawny moduł.

Krok 2: wyrwij statyczne fragmenty do HTML-a

Wiele „aplikacji” legacy renderuje przez ciężki framework rzeczy, które są w istocie statyczne: nagłówki, opisy, sekcje marketingowe. Przenieś je do natywnego Astro (czysty HTML). Każdy taki fragment to JavaScript, którego już nie wysyłasz — strona przyspiesza, a Ty nie dotknąłeś krytycznej logiki.

To zwykle najtańszy zysk. Sekcja hero, lista benefitów, porównanie pakietów, statyczne FAQ albo bloki case study nie potrzebują stanu frameworka. W Astro mogą zostać zwykłym HTML-em, komponentem .astro albo treścią z MDX/CMS. Jeśli wcześniej żyły w Reactcie tylko dlatego, że cały projekt był Reactowy, migracja usuwa koszt bez zmiany logiki biznesowej.

Krok 3: wymieniaj panele po jednym, w nowym frameworku

Tu wkracza wieloframeworkowość. Nowe lub przebudowywane panele możesz pisać w lżejszym frameworku (np. Svelte, który kompiluje się do szczupłego, beznarzutowego JavaScriptu i wyjątkowo dobrze współgra z filozofią Astro), podczas gdy stare panele wciąż działają w Reactcie obok. Wymieniasz je pojedynczo, wyspa po wyspie, każdy za osobnym, bezpiecznym deployem. Produkcja nigdy nie stoi.

Nie traktuj tego jako zachęty do technologicznego chaosu. Nowy framework powinien mieć uzasadnienie: mniejszy koszt runtime, kompetencje zespołu, lepsza biblioteka do konkretnego widgetu albo plan stopniowego wygaszania starego Reacta/Vue. Jeśli każdy nowy komponent powstaje w innym frameworku „bo można”, Astro nie rozwiązuje długu technicznego — tylko go estetycznie opakowuje.

Krok 4: domknij migrację, gdy to ma sens

Nie ma przymusu, by skończyć „na 100%”. Jeśli stary panel działa stabilnie i rzadko się zmienia, może spokojnie zostać w Reactcie jako wyspa client:visible. Migrujesz to, co aktywnie rozwijasz i co realnie obciąża wydajność — resztę zostawiasz w spokoju. To racjonalne zarządzanie długiem, nie dogmatyczne przepisywanie.

Komunikacja między wyspami

Wyspy Astro są niezależne i to spora zalet pod kątem wydajności, ale z drugiej strony ograniczenie dla architektury. Reactowy komponent nie dzieli automatycznie stanu z komponentem Vue, a Svelte store nie jest widoczny w starym panelu Reacta.

Masz więc trzy opcje.

1. Props z rodzica Astro. Najprostsze rozwiązanie dla danych początkowych: locale, feature flag, początkowy filtr, identyfikator produktu, wariant A/B.

Code
---
import PriceCalculator from '../components/PriceCalculator.svelte'
 
const plan = Astro.url.searchParams.get('plan') ?? 'growth'
---
 
<PriceCalculator client:visible initialPlan={plan} />

2. URL jako wspólny kontrakt. Dobre dla filtrów, paginacji i stanów, które mają być linkowalne. React może zapisać ?q=astro&sort=price, a Svelte lub Vue może odczytać ten sam parametr po wejściu użytkownika w kolejną sekcję.

3. Zdarzenia DOM albo mały store cross-framework. Jeśli wyspy muszą zareagować na siebie na tej samej stronie, użyj jawnego kontraktu:

Code
// React island
window.dispatchEvent(
  new CustomEvent('legacy:filters-changed', {
    detail: { category: 'hosting', price: 'low' },
  }),
)
Code
<!-- Svelte island -->
<script lang="ts">
  import { onMount } from 'svelte'
 
  let category = ''
 
  onMount(() => {
    const handleFilters = (event: Event) => {
      const customEvent = event as CustomEvent<{ category: string }>
      category = customEvent.detail.category
    }
 
    window.addEventListener('legacy:filters-changed', handleFilters)
    return () => window.removeEventListener('legacy:filters-changed', handleFilters)
  })
</script>

Jeśli takich połączeń robi się dużo, to sygnał ostrzegawczy. Jedna lub dwie jawne integracje między wyspami są normalne. Gęsta siatka eventów oznacza, że prawdopodobnie budujesz aplikację z dużym współdzielonym stanem i powinieneś wrócić do jednego frameworka aplikacyjnego.

Budżet JavaScriptu i pomiar efektu

Migracja legacy ma sens tylko wtedy, gdy poprawia realny stan projektu: mniej JavaScriptu, szybsze wejście w interakcję, prostsze wdrożenia albo mniejszy koszt utrzymania. Dlatego przed migracją zapisz stan wyjściowy: rozmiar JS dla trasy, liczbę hydratowanych wysp oraz LCP, INP i TBT z Lighthouse albo WebPageTest. Do tego zbierz błędy z konsoli i Sentry, najcięższe zależności z bundle analyzera oraz krytyczne eventy biznesowe, jak wysłanie formularza czy kliknięcie CTA.

Po każdym etapie porównujesz wynik. Jeśli wyciągnięcie statycznych sekcji do .astro obniżyło JS o 80 KB, to masz twardy argument za kontynuacją. Jeśli przeniesienie jednego widgetu do Svelte dołożyło dodatkowy runtime na stronie, która i tak ma Reacta, decyzja może być gorsza niż wyglądała w pull requeście.

Praktyczna zasada: nie mieszaj frameworków bez budżetu. Dopuszczalne jest przejściowe posiadanie Reacta i Vue na jednej stronie, jeśli to etap migracji. Nie jest dopuszczalne dokładanie trzeciego runtime’u bez jasnego powodu i pomiaru kosztu.

Rollout, testy i rollback

Migracja legacy powinna iść mniejszymi deployami niż zwykły feature. Każdy krok zmienia nie tylko kod, ale też sposób ładowania, hydratacji i komunikacji z przeglądarką.

Minimalny plan wdrożenia wygląda tak:

  1. Wybierz moduł o niskim lub średnim ryzyku, ale mierzalnym koszcie.
  2. Owiń go adapterem i uruchom jako wyspę bez zmiany logiki.
  3. Dodaj test E2E dla głównego scenariusza użytkownika.
  4. Zmierz bundle, Lighthouse i błędy runtime przed/po.
  5. Włącz feature flagę, jeśli moduł obsługuje krytyczną ścieżkę.
  6. Wdróż na małym zakresie, obserwuj błędy i eventy konwersji.
  7. Dopiero potem wyciągaj statykę albo przepisuj kolejny panel.

Rollback też musi być prosty. Jeśli nowa wyspa psuje formularz lub tracking, wracasz do starego komponentu przez flagę albo szybki revert pojedynczego modułu. To właśnie różni migrację inkrementalną od pełnego przepisywania systemu: porażka jednego kroku nie zatrzymuje całego projektu.

Czego nie migrować

Najdojrzalsza decyzja migracyjna często brzmi: „tego nie ruszamy”. Nie warto przepisywać modułu tylko dlatego, że jest stary.

Zostaw stary framework, jeśli:

  • moduł jest stabilny, rzadko zmieniany i nie obciąża istotnie strony,
  • ma dużo ukrytych reguł biznesowych, których nikt już dobrze nie pamięta,
  • dotyczy krytycznej konwersji, a nie masz jeszcze testów E2E,
  • zależy od globalnego stanu aplikacji bardziej niż wynika z pierwszego audytu,
  • przepisywanie nie zmniejszy JS, nie uprości utrzymania i nie odblokuje rozwoju.

Migruj najpierw miejsca, które są jednocześnie kosztowne i względnie izolowane. To tam Astro daje największy zwrot: zmniejszasz ciężar strony bez otwierania całej architektury naraz.

Pułapki, o których warto wiedzieć

  • Współdzielony stan między wyspami. Wyspy są odizolowane — nie dzielą stanu Reacta czy store’a Vue „z automatu”. Komunikację między nimi realizuj przez zdarzenia DOM, (działa cross-framework) lub parametry przekazane z rodzica Astro.
  • client:only a . Komponent oznaczony client:only nie renderuje się na serwerze, więc nie pojawi się w pierwszym HTML — zadbaj o sensowny placeholder, by uniknąć przeskoku layoutu.
  • Globalny CSS. Stare aplikacje często zakładają jeden globalny arkusz. Po przeniesieniu do Astro łatwo o przecieki styli między wyspami. Krytyczne moduły izoluj przez CSS Modules, scoped styles, klasy z prefiksem albo osobny wrapper.
  • Różne wersje zależności. Dwa moduły mogą wymagać innych wersji biblioteki UI, klienta API albo helperów dat. Przed migracją sprawdź lockfile i bundle, bo „działa lokalnie” nie znaczy, że koszt produkcyjny jest akceptowalny.
  • Analityka i tracking. Jeśli stary komponent wysyła eventy konwersji, migracja musi zachować nazwy eventów, parametry i moment wysyłki. Inaczej poprawisz architekturę, ale popsujesz dane marketingowe.
  • Zbyt szybkie przepisywanie. Jeśli pierwszy krok zmienia framework, UI, logikę i tracking jednocześnie, nie będziesz wiedzieć, co zepsuło produkcję. Najpierw opakuj, potem upraszczaj.

Kiedy Astro nie jest właściwą warstwą

Astro jest świetne jako warstwa dla stron treściowych, marketingowych, dokumentacyjnych i hybrydowych. Nie jest jednak automatycznie najlepszym rdzeniem dla każdej aplikacji legacy.

Nie pchałbym całego produktu do Astro, w sytuacji, kiedy:

  • Większość ekranów wymaga logowania i dynamicznych danych użytkownika

  • Komponenty współdzielają dużo stanu w czasie rzeczywistym

  • Routing aplikacyjny jest częścią logiki produktu
  • Zespół ma już spójny stack i nie ma realnego problemu migracyjnego

  • Plan wymaga kilku frameworków na stałe, a nie przejściowo

  • Każda wyspa musi stale rozmawiać z każdą inną wyspą

W takim układzie lepsza może być aplikacja w jednym frameworku, a Astro jako osobny front marketingowy, blog, dokumentacja lub publiczna baza wiedzy. Granica jest prosta: jeśli użytkownik głównie czyta i wykonuje punktowe interakcje, Astro pasuje. Jeśli użytkownik pracuje w aplikacji przez wiele ekranów i cały czas zmienia stan systemu, jeden framework aplikacyjny będzie zdrowszy.

Ultraszybkie projekty, łączące lekkość ze skalowalnością.
Astro

Często zadawane pytania

Czy mogę naprawdę mieć React, Vue i Svelte na jednej stronie?

Tak. Astro oficjalnie wspiera ten scenariusz, możesz mieszać frameworki na poziomie strony Astro. Ograniczenie dotyczy tylko tego, że pojedynczy plik komponentu nie mieszał frameworków w środku.

Przejściowo na stronach z wieloma frameworkami naraz pobierane są ich runtime’y. Dlatego docelowo warto konsolidować framework per strona. Ale dyrektywy client: (zwłaszcza client:visible) sprawiają, że płacisz za JavaScript tylko tam i wtedy, gdy jest potrzebny.

Nie dzielą stanu automatycznie. Komunikację realizujesz przez zdarzenia DOM, bibliotekę typu nanostores (działa między frameworkami) lub propsy przekazane przez rodzica Astro.

Nie. Migruj to, co aktywnie rozwijasz i co obciąża wydajność. Stabilne, rzadko zmieniane panele mogą zostać w starym frameworku jako wyspy hydratowane leniwie. To zarządzanie długiem, nie dogmat.

Od inwentaryzacji modułów: które są statyczne, które mają stan, które są krytyczne biznesowo, które zależą od globalnego store’a, routera, CSS albo zewnętrznych skryptów. Dopiero po takim audycie wybierasz pierwszą wyspę do migracji.

Gdy projekt jest pełną aplikacją z dużym współdzielonym stanem, jednym zespołem pracującym w spójnym stacku albo silną zależnością między ekranami. Wtedy lepszy jest jeden framework aplikacyjny niż kilka izolowanych wysp.

O autorze

Maciej Sala

Maciej Sala — Product Manager i Frontend Developer z bogatym doświadczeniem w marketingu internetowym oraz SEO. Na co dzień pracuje z Reactem, Next.js i TypeScriptem, a ostatnio także z Astro i narzędziami do automatyzacji procesów AI. Sprawnie łączy perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat był związany z branżą gier wideo jako project manager i game designer. Absolwent historii na Uniwersytecie Jagiellońskim oraz studiów podyplomowych z marketingu internetowego na AGH w Krakowie. Po godzinach trenuje na siłowni, maluje figurki i rozwijam własne projekty.

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną

Biblioteka wiedzy

Czytaj dalej

Zobacz więcej wpisów
Wieloframeworkowa architektura wysp w Astro: React, Vue i Svelte w jednym projekcie

Zero JavaScript by default to chwytliwy slogan. Architektura, którą on opisuje, to coś większego: cały projekt może być statycznym HTML, a interaktywność — precyzyjnie rozmieszczonymi wyspami. Każda wyspa to niezależna jednostka z własnym frameworkiem, własnym cyklem hydratacji i własnym kosztem runtime. React, Vue, Svelte, Solid — na jednej stronie, pod jedną konfiguracją Astro. To nie eksperyment — to strategia migracji i narzędzie dla organizacji, które nie mogą sobie pozwolić na przepisanie wszystkiego od zera.

Maciej Sala

Maciej Sala

Founder StriveLab

Architektura wysp w Astro — czym są wyspy i dlaczego zero JS domyślnie zmienia zasady gry

Zero JavaScript domyślnie brzmi jak jakaś reklama, ale dane jasno pokazują, że to architektoniczna decyzja, która daje do myślenia: Lighthouse powyżej 95, TBT bliski zera, Google dostaje czysty HTML od razu. Klasyczne aplikacje SPA wysyłają do przeglądarki cały framework, nawet jeśli większość strony to statyczna treść. W tym artykule rozkładam mechanizm wysp na części i pokazuję, kiedy daje realne korzyści, a kiedy nie.

Maciej Sala

Maciej Sala

Founder StriveLab

Astro.js vs Next.js w 2026 — kompleksowe porównanie frameworków

Artykuł nie jest manifestem o porzuceniu jednej technologii na rzecz drugiej, lecz bardziej analizą, w której staram się pokazać obiektywnie, w których obszarach Astro dostarcza bezdyskusyjną przewagę wydajnościową, a w jakich scenariuszach Next.js pozostaje niezastąpionym wyborem.

Maciej Sala

Maciej Sala

Founder StriveLab