Astro - Nowoczesny generator stron z architekturą Islands
Astro Nowoczesny generator
frontendAstro - Nowoczesny generator stron statycznych
Astro to framework webowy nowej generacji, ktory fundamentalnie zmienia podejscie do budowy stron internetowych. Zamiast wysylac do przegladarki kilogramy JavaScriptu, Astro generuje czyste HTML i CSS, dodajac JavaScript tylko tam, gdzie jest naprawde potrzebny. Ta filozofia "zero JS by default" sprawia, ze strony zbudowane w Astro sa jednym z najszybszych rozwiazan dostepnych na rynku.
W tym artykule przyjrzymy sie kluczowym koncepcjom Astro - od architektury Islands, przez komponenty .astro, Content Collections, az po tryb SSR i porownanie wydajnosci z Next.js oraz Gatsby.
Architektura Islands - rewolucja w budowie interfejsow#
Architektura Islands (wyspy) to kluczowa innowacja Astro. Tradycyjne frameworki SPA traktuja cala strone jako jedna wielka aplikacje JavaScript - nawet jesli wiekszosc tresci jest statyczna. Astro odwraca ten model.
Jak dzialaja Islands?#
W Astro kazda strona jest domyslnie statycznym HTML. Interaktywne elementy - przyciski, formularze, karuzele - sa traktowane jako niezalezne "wyspy" JavaScript osadzone w morzu statycznego HTML:
---
// src/pages/index.astro
import Header from '../components/Header.astro';
import HeroSection from '../components/HeroSection.astro';
import ProductCarousel from '../components/ProductCarousel.tsx';
import Newsletter from '../components/Newsletter.vue';
import Footer from '../components/Footer.astro';
---
<html lang="pl">
<body>
<!-- Statyczny HTML - zero JavaScript -->
<Header />
<HeroSection />
<!-- Interaktywna "wyspa" - React, ladowana przy widocznosci -->
<ProductCarousel client:visible />
<!-- Interaktywna "wyspa" - Vue, ladowana od razu -->
<Newsletter client:load />
<!-- Statyczny HTML -->
<Footer />
</body>
</html>
Dyrektywy client#
Astro oferuje precyzyjna kontrole nad tym, kiedy JavaScript zostaje zaladowany:
client:load- laduje komponent natychmiast po zaladowaniu stronyclient:idle- laduje, gdy przegladarka jest bezczynna (requestIdleCallback)client:visible- laduje, gdy komponent pojawi sie w widoku (Intersection Observer)client:media- laduje przy spelnieniu warunku media queryclient:only- renderuje komponent wylacznie po stronie klienta
---
import HeavyChart from '../components/HeavyChart.tsx';
import MobileMenu from '../components/MobileMenu.svelte';
import ChatWidget from '../components/ChatWidget.tsx';
---
<!-- Wykres ladowany dopiero gdy uzytkownik do niego przewinie -->
<HeavyChart client:visible />
<!-- Menu mobilne ladowane tylko na malych ekranach -->
<MobileMenu client:media="(max-width: 768px)" />
<!-- Chat ladowany gdy przegladarka jest bezczynna -->
<ChatWidget client:idle />
Ta granularna kontrola oznacza, ze uzytkownik pobiera JavaScript tylko wtedy, gdy go potrzebuje - i tylko tyle, ile potrzebuje.
Zero JavaScript by default#
W przeciwienstwie do Next.js czy Gatsby, gdzie kazda strona zawiera runtime Reacta (ok. 40-80 KB gzipped), Astro domyslnie nie wysyla zadnego JavaScriptu. Strona zbudowana wylacznie z komponentow .astro generuje czysty HTML i CSS.
---
// src/components/BlogCard.astro
// Ten komponent renderuje sie do czystego HTML - zero JS
interface Props {
title: string;
excerpt: string;
date: string;
slug: string;
}
const { title, excerpt, date, slug } = Astro.props;
const formattedDate = new Date(date).toLocaleDateString('pl-PL', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
---
<article class="blog-card">
<time datetime={date}>{formattedDate}</time>
<h3><a href={`/blog/${slug}`}>{title}</a></h3>
<p>{excerpt}</p>
</article>
<style>
.blog-card {
padding: 1.5rem;
border-radius: 8px;
background: var(--surface);
transition: transform 0.2s ease;
}
.blog-card:hover {
transform: translateY(-2px);
}
</style>
Caly powyzszy komponent kompiluje sie do statycznego HTML i CSS z zasiegiem lokalnym (scoped styles). Przegladarka nie musi pobierac ani parsowac zadnego JavaScriptu.
Framework agnostic - uzyj React, Vue, Svelte lub wszystkich naraz#
Jedyna z najbardziej unikalnych cech Astro jest mozliwosc mieszania komponentow z roznych frameworkow w jednym projekcie. Mozesz uzyc komponentu React obok komponentu Vue i komponentu Svelte - Astro zajmie sie reszta.
Konfiguracja integracji#
// 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({
integrations: [react(), vue(), svelte()],
});
Praktyczny przyklad#
---
// src/pages/dashboard.astro
// Kazdy komponent uzywa frameworka, w ktorym zostal napisany
import ReactDataGrid from '../components/DataGrid.tsx';
import VueFormWizard from '../components/FormWizard.vue';
import SvelteNotifications from '../components/Notifications.svelte';
---
<main>
<h1>Panel administracyjny</h1>
<!-- React - doskonaly do zlozonych tabel z danymi -->
<ReactDataGrid client:load data={dashboardData} />
<!-- Vue - swietny do wieloetapowych formularzy -->
<VueFormWizard client:visible />
<!-- Svelte - lekki i szybki do powiadomien -->
<SvelteNotifications client:idle />
</main>
To podejscie jest szczegolnie wartosciowe podczas migracji - mozesz stopniowo przenosic komponenty z jednego frameworka na drugi bez koniecznosci przepisywania calej aplikacji.
Komponenty .astro - sila prostoty#
Komponenty .astro to natywny format Astro, laczacy logike serwera z szablonem HTML w jednym pliku. Skladnia przypomina polaczenie JSX z frontmatterem:
---
// src/components/Navigation.astro
// Blok "fence" --- wykonuje sie na serwerze
interface Props {
currentPath: string;
}
const { currentPath } = Astro.props;
const navItems = [
{ href: '/', label: 'Strona glowna' },
{ href: '/uslugi', label: 'Uslugi' },
{ href: '/portfolio', label: 'Portfolio' },
{ href: '/blog', label: 'Blog' },
{ href: '/kontakt', label: 'Kontakt' },
];
// Mozesz uzywac await na najwyzszym poziomie
const response = await fetch('https://api.example.com/announcements');
const announcements = await response.json();
---
<nav class="main-nav">
<ul>
{navItems.map((item) => (
<li>
<a
href={item.href}
class:list={[
'nav-link',
{ active: currentPath === item.href }
]}
>
{item.label}
</a>
</li>
))}
</ul>
{announcements.length > 0 && (
<div class="announcement-bar">
{announcements[0].message}
</div>
)}
</nav>
<style>
.nav-link {
text-decoration: none;
color: var(--text);
padding: 0.5rem 1rem;
}
.nav-link.active {
color: var(--primary);
font-weight: 600;
}
</style>
Kluczowe cechy komponentow .astro:
- Top-level await - mozesz pobierac dane bezposrednio w komponencie
- Scoped styles - style sa domyslnie izolowane do komponentu
- Brak reaktywnosci - renderuja sie raz na serwerze, co czyni je ekstremalnie szybkimi
- TypeScript out-of-the-box - pelne wsparcie bez dodatkowej konfiguracji
Content Collections - typowane zarzadzanie trescia#
Content Collections to wbudowany system zarzadzania trescia w Astro. Pozwala organizowac posty blogowe, dokumentacje czy produkty z pelna walidacja typow.
Definiowanie kolekcji#
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blogCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string().max(160),
date: z.coerce.date(),
updated: z.coerce.date().optional(),
category: z.enum(['frontend', 'backend', 'devops', 'mobile']),
tags: z.array(z.string()),
author: z.string().default('MDS Software Solutions Group'),
cover: z.string(),
draft: z.boolean().default(false),
locale: z.enum(['pl', 'en', 'de']),
}),
});
const projectsCollection = defineCollection({
type: 'content',
schema: z.object({
name: z.string(),
client: z.string(),
technologies: z.array(z.string()),
year: z.number(),
featured: z.boolean().default(false),
}),
});
export const collections = {
blog: blogCollection,
projects: projectsCollection,
};
Pobieranie i wyswietlanie tresci#
---
// src/pages/blog/[...slug].astro
import { getCollection, getEntry } from 'astro:content';
import BlogLayout from '../../layouts/BlogLayout.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog', ({ data }) => {
return data.draft !== true && data.locale === 'pl';
});
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
const { Content, headings } = await post.render();
---
<BlogLayout frontmatter={post.data}>
<nav class="toc">
<h2>Spis tresci</h2>
<ul>
{headings
.filter((h) => h.depth <= 3)
.map((h) => (
<li style={`margin-left: ${(h.depth - 2) * 1}rem`}>
<a href={`#${h.slug}`}>{h.text}</a>
</li>
))}
</ul>
</nav>
<Content />
</BlogLayout>
Content Collections automatycznie waliduja frontmatter, generuja typy TypeScript i oferuja pelen IntelliSense w edytorze kodu.
Routing oparty na plikach#
Astro uzywa systemu routingu opartego na strukturze plikow w katalogu src/pages/. Jest intuicyjny i nie wymaga zadnej konfiguracji:
src/pages/
index.astro -> /
about.astro -> /about
blog/
index.astro -> /blog
[slug].astro -> /blog/:slug (dynamiczny)
[...slug].astro -> /blog/* (catch-all)
api/
search.ts -> /api/search (endpoint API)
Dynamiczne trasy z parametrami#
---
// src/pages/kategoria/[category].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
const categories = [...new Set(posts.map((p) => p.data.category))];
return categories.map((category) => ({
params: { category },
props: {
posts: posts.filter((p) => p.data.category === category),
},
}));
}
const { category } = Astro.params;
const { posts } = Astro.props;
---
<h1>Kategoria: {category}</h1>
<ul>
{posts.map((post) => (
<li>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
</li>
))}
</ul>
Endpointy API#
// src/pages/api/search.ts
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';
export const GET: APIRoute = async ({ url }) => {
const query = url.searchParams.get('q')?.toLowerCase() || '';
const posts = await getCollection('blog');
const results = posts
.filter((post) =>
post.data.title.toLowerCase().includes(query) ||
post.data.description.toLowerCase().includes(query)
)
.map((post) => ({
title: post.data.title,
slug: post.slug,
description: post.data.description,
}));
return new Response(JSON.stringify(results), {
headers: { 'Content-Type': 'application/json' },
});
};
View Transitions API - plynne przejscia miedzy stronami#
Astro jako jeden z pierwszych frameworkow zintegrowalo natywne View Transitions API, umozliwiajac plynne animacje przejsc miedzy stronami bez uzycia SPA:
---
// src/layouts/BaseLayout.astro
import { ViewTransitions } from 'astro:transitions';
---
<html lang="pl">
<head>
<ViewTransitions />
</head>
<body>
<slot />
</body>
</html>
Niestandardowe animacje#
---
// src/components/BlogCard.astro
import { fade, slide } from 'astro:transitions';
---
<article transition:animate={slide({ duration: '0.3s' })}>
<img
src={cover}
alt={title}
transition:name={`blog-cover-${slug}`}
/>
<h3 transition:name={`blog-title-${slug}`}>
{title}
</h3>
</article>
Dzieki transition:name Astro automatycznie animuje elementy z tym samym identyfikatorem miedzy stronami - np. miniatura posta na liscie plynnie przechodzi w duzy obraz na stronie posta.
Tryb SSR - renderowanie po stronie serwera#
Astro wspiera rowniez dynamiczne renderowanie po stronie serwera (SSR), co umozliwia budowe pelnych aplikacji webowych:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
output: 'server', // lub 'hybrid' dla mieszanego podejscia
adapter: node({
mode: 'standalone',
}),
});
Tryb hybrydowy#
Tryb hybrid pozwala domyslnie pre-renderowac strony, z mozliwoscia oznaczenia wybranych jako dynamiczne:
---
// src/pages/dashboard.astro
// Ta strona bedzie renderowana dynamicznie
export const prerender = false;
import { getSession } from '../lib/auth';
const session = await getSession(Astro.request);
if (!session) {
return Astro.redirect('/login');
}
---
<h1>Witaj, {session.user.name}!</h1>
Astro oferuje adaptery dla roznych platform deploymentowych: Node.js, Vercel, Netlify, Cloudflare Workers, Deno i inne.
Integracje - Tailwind, MDX i wiele wiecej#
Ekosystem Astro oferuje bogaty zestaw oficjalnych i spolecznosciowych integracji:
# Instalacja integracji jednym poleceniem
npx astro add tailwind
npx astro add mdx
npx astro add sitemap
npx astro add image
Konfiguracja z Tailwind CSS#
// astro.config.mjs
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
integrations: [
tailwind({
applyBaseStyles: false,
}),
mdx(),
sitemap({
filter: (page) => !page.includes('/admin/'),
}),
],
});
MDX z niestandardowymi komponentami#
---
title: Jak zoptymalizowac wydajnosc strony
---
import Callout from '../../components/Callout.astro';
import CodePlayground from '../../components/CodePlayground.tsx';
# Jak zoptymalizowac wydajnosc strony
<Callout type="tip">
Astro automatycznie optymalizuje obrazy - nie musisz konfigurowac dodatkowych narzedzi.
</Callout>
## Przyklad na zywo
<CodePlayground client:visible code={`console.log('Hello Astro!')`} />
Optymalizacja obrazow#
Astro oferuje wbudowana optymalizacje obrazow poprzez komponent <Image />:
---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<!-- Automatyczna optymalizacja: konwersja do WebP/AVIF, responsywne rozmiary -->
<Image
src={heroImage}
alt="Opis obrazu"
widths={[400, 800, 1200]}
sizes="(max-width: 800px) 100vw, 800px"
format="webp"
quality={80}
/>
<!-- Obrazy zdalne z podanymi wymiarami -->
<Image
src="https://example.com/photo.jpg"
alt="Zdalne zdjecie"
width={800}
height={600}
format="avif"
/>
Astro automatycznie generuje odpowiednie rozmiary, konwertuje do nowoczesnych formatow i dodaje atrybuty width/height zapobiegajace layout shift (CLS).
Astro DB - wbudowana baza danych#
Astro DB to rozwiazanie bazodanowe oparte na libSQL (fork SQLite), zaprojektowane specjalnie do wspolpracy z Astro:
// db/config.ts
import { defineDb, defineTable, column } from 'astro:db';
const Comment = defineTable({
columns: {
id: column.number({ primaryKey: true }),
postSlug: column.text(),
author: column.text(),
content: column.text(),
createdAt: column.date({ default: new Date() }),
approved: column.boolean({ default: false }),
},
});
export default defineDb({
tables: { Comment },
});
---
// src/pages/blog/[slug].astro
import { db, Comment, eq } from 'astro:db';
const comments = await db
.select()
.from(Comment)
.where(eq(Comment.postSlug, slug))
.where(eq(Comment.approved, true))
.orderBy(Comment.createdAt);
---
<section class="comments">
{comments.map((comment) => (
<div class="comment">
<strong>{comment.author}</strong>
<p>{comment.content}</p>
<time>{comment.createdAt.toLocaleDateString('pl-PL')}</time>
</div>
))}
</section>
Porownanie wydajnosci z Next.js i Gatsby#
Astro konsekwentnie wygrywa w benchmarkach wydajnosci dla stron treściowych (content-driven sites):
Rozmiar JavaScript wysylany do klienta#
| Framework | Strona glowna (typowa) | Blog post | |-----------|----------------------|-----------| | Astro | 0 KB | 0 KB | | Next.js | ~85 KB | ~85 KB | | Gatsby | ~70 KB | ~70 KB |
Metryki Core Web Vitals (typowa strona blogowa)#
| Metryka | Astro | Next.js | Gatsby | |---------|-------|---------|--------| | LCP | ~0.8s | ~1.5s | ~1.8s | | FID | ~5ms | ~30ms | ~25ms | | CLS | 0 | ~0.05 | ~0.08 | | TTFB | ~50ms | ~80ms | ~60ms |
Roznica jest szczegolnie widoczna na urzadzeniach mobilnych z wolnym polaczeniem - brak JavaScriptu do pobrania i parsowania oznacza blyskawiczne zaladowanie strony.
Czas budowania (1000 stron Markdown)#
| Framework | Czas budowania | |-----------|---------------| | Astro | ~15s | | Next.js | ~45s | | Gatsby | ~90s |
Kiedy wybrac Astro?#
Astro jest idealny do:#
- Blogów i stron contentowych - maksymalna wydajnosc dla tresci statycznych
- Stron firmowych i portfolio - szybkie ladowanie, swietne SEO
- Dokumentacji technicznej - Content Collections i MDX
- Landing page - minimalna ilosc JS, natychmiastowe ladowanie
- Stron e-commerce - szybkosc ladowania bezposrednio wplywa na konwersje
- Stron wielojezycznych - wbudowane wsparcie dla i18n
Kiedy rozwazyc inne rozwiazania:#
- Zlożone aplikacje SPA (np. dashboardy real-time) - Next.js lub SvelteKit
- Aplikacje wymagajace ciaglej interaktywnosci - React/Vue SPA
- Full-stack z ciezkim backendem - Next.js, Remix lub NestJS
Szybki start z Astro#
# Utworzenie nowego projektu
npm create astro@latest my-astro-site
# Przejscie do katalogu projektu
cd my-astro-site
# Dodanie integracji
npx astro add tailwind
npx astro add mdx
# Uruchomienie serwera deweloperskiego
npm run dev
Podsumowanie#
Astro to framework, ktory zmienia zasady gry w budowie stron internetowych. Dzieki architekturze Islands, podejsciu "zero JavaScript by default" i wsparciu dla wielu frameworkow, oferuje unikalne polaczenie wydajnosci i elastycznosci.
Jesli budujesz strone, gdzie treść jest kluczowa - blog, witryne firmowa, dokumentacje czy landing page - Astro powinno byc Twoim pierwszym wyborem. Wyniki w Core Web Vitals mowia same za siebie.
Planujesz budowe nowoczesnej strony internetowej z nastawieniem na wydajnosc i SEO? Zespol MDS Software Solutions Group specjalizuje sie w tworzeniu wydajnych aplikacji webowych z uzyciem Astro, Next.js i innych nowoczesnych technologii. Skontaktuj sie z nami - pomozemy Ci wybrac najlepsze rozwiazanie i zbudowac strone, ktora zachwyci szybkoscia dzialania.
Zespół ekspertów programistycznych specjalizujących się w nowoczesnych technologiach webowych.