Kiedy zabraliśmy się za przebudowę strony Basi Software, oczywistym wyborem okazał się Next.js. Stosujemy go na co dzień w projektach dla klientów. Nasz zespół zna go na wylot.
Zamiast tego zdecydowaliśmy się na Astro. Oto dlaczego — i czego się nauczyliśmy.
Podatek SPA
Aplikacje jednostronicowe przeniosły obciążenie związane z renderowaniem z serwera na stronę klienta. W przypadku aplikacji o wysokim stopniu interaktywności — pulpitów nawigacyjnych, edytorów, narzędzi do współpracy — jest to właściwy kompromis. Natomiast w przypadku strony marketingowej z formularzem kontaktowym stanowi to obciążenie.
„Podatek SPA” jest wykazany jako:
- JavaScript dostarczony na potrzeby interakcji, które nigdy nie mają miejsca — użytkownik czyta opis bohatera, przewija stronę i opuszcza ją. Nigdy nie kliknął elementu wyzwalającego okno modalne. A mimo to wdrożyłeś kod JavaScript obsługujący to okno.
- Wodospady nawadniające — React odświeża całe drzewo, zanim jakakolwiek interakcja stanie się możliwa
- Zmiana układu — kod HTML renderowany po stronie serwera zostaje zastąpiony kodem HTML renderowanym po stronie klienta, co powoduje CLS
# Lighthouse on our old Next.js site (production build)
Performance: 71
First Contentful Paint: 1.8s
Total Blocking Time: 340ms
JavaScript bundle: ~280kb (gzipped)
# After migrating to Astro
Performance: 98
First Contentful Paint: 0.6s
Total Blocking Time: 0ms
JavaScript bundle: ~6kb (only the Nav and ContactForm islands)
Co tak naprawdę oznacza architektura wyspiarska Astro
Termin „wyspy” został ukuty przez Katie Sylor-Miller z serwisu Etsy. Idea polega na tym, że na stronie, która w innym przypadku byłaby statyczna, znajdują się odizolowane „wyspy” interaktywności. Każda wyspa ładuje się niezależnie. Cała pozostała część strony jest dostarczana jako kod HTML bez JavaScriptu.
---
// Layout.astro — the shell is pure HTML
import Nav from '../components/Nav.astro'; // Static shell + small script
import ContactForm from './ContactForm'; // React island
import HeroSection from './HeroSection.astro'; // Zero JS — static HTML
---
<body>
<!-- Astro component — no framework runtime required -->
<Nav />
<main>
<!-- Static Astro component — ships as HTML, zero runtime cost -->
<HeroSection />
</main>
</body>
Formularz kontaktowy jest tutaj jedyną wyspą frameworkową. Nawigacja zachowuje swoje interaktywne zachowanie dzięki niewielkiemu skryptowi przeglądarkowemu, dzięki czemu nie powoduje ona wciągania Reacta na każdą stronę.
Najważniejsze dyrektywy
Astro przedstawia pięć wytycznych dotyczących nawadniania. Wybór odpowiedniej z nich ma wymierny wpływ:
| Wytyczna | Kiedy nawilża | Zastosowanie |
|---|---|---|
client:load | Natychmiast | Nawigacja, interaktywna w górnej części strony |
client:idle | Gdy przeglądarka jest w stanie bezczynności | Elementy poniżej linii zgięcia |
client:visible | Gdy element pojawi się w polu widzenia | Komponenty ładowane z opóźnieniem |
client:media | Gdy zapytanie o media jest spełnione | Widżety przeznaczone wyłącznie dla urządzeń mobilnych |
client:only | Wyłącznie po stronie klienta, bez SSR | Komponenty zależne od API przeglądarki |
W przypadku większości serwisów marketingowych, client:visible jest właściwym ustawieniem domyślnym dla wszystkich elementów znajdujących się poniżej linii zgięcia.
Wyświetlanie przejść bez użycia frameworka
Jednym z powodów, dla których zespoły wybierają Next.js, jest wbudowany router z efektami przejścia między stronami. Astro również to oferuje, dzięki <ClientRouter /> komponent oraz interfejs API przejść między widokami.
---
import { ClientRouter } from 'astro:transitions';
---
<head>
<ClientRouter />
</head>
/* Custom transition — runs on every page navigation */
::view-transition-old(root) {
animation: fade-out 0.3s ease-in forwards;
}
::view-transition-new(root) {
animation: slide-up 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
Ten transition:persist Atrybut w elemencie `Nav` oznacza, że nie jest on ponownie montowany przy przechodzeniu między stronami — wyspa Reacta pozostaje aktywna, zachowując pozycję przewijania oraz stan otwarcia/zamknięcia.
Zbiory treści zapewniające bezpieczeństwo typów
Ten blog działa w oparciu o kolekcje treści Astro — warstwę treści opartą na TypeScript, zatwierdzoną przez Zod:
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
category: z.string(),
tags: z.array(z.string()).default([]),
}),
});
export const collections = { blog };
Każdy plik MDX w src/content/blog/ jest teraz w pełni typowany. Jeśli w poście brakuje obowiązkowego pola, kompilacja kończy się niepowodzeniem — nie jest to błąd wykonawczy w środowisku produkcyjnym.
Kiedy warto sięgnąć po Next.js
Astro nie jest odpowiedzią na wszystko:
- Aplikacje o wysokim stopniu interaktywności — jeśli większość strony ma działać w oparciu o React, wdrażaj React. Witryna Astro z
client:loadw przypadku każdego komponentu jest gorsza niż w Next.js. - Funkcje działające w czasie rzeczywistym — interaktywne pulpity nawigacyjne, edycja w trybie współpracy oraz interfejsy użytkownika intensywnie wykorzystujące WebSocket powinny być realizowane w ramach pełnoprawnej aplikacji typu SPA
- Duże aplikacje wymagające uwierzytelnienia — procesy uwierzytelniania, dynamiczne przekierowania oparte na danych użytkownika, złożony stan po stronie klienta — w tym zakresie wygrywa Next.js
Zasada: jeśli większość twoich stron zawiera przede wszystkim przeczytaj zamiast wchodził w interakcje z, Astro to lepszy punkt wyjścia.
Wnioski
Powrót do architektury wielostronicowej nie jest krokiem wstecz. Jest to uznanie faktu, że natywny model sieci — dokumenty połączone hiperłączami — nadal stanowi najbardziej wydajną, dostępną i odporną architekturę dla witryn, w których treść odgrywa pierwszoplanową rolę.
Dzięki Astro tworzenie w ten sposób w 2026 roku będzie po prostu przyjemnością.
Comments
Loading comments…