Przejdź do treści
Frontend

Astro - Nowoczesny generator stron z architekturą Islands

Opublikowano:
·6 min czytania·Autor: MDS Software Solutions Group

Astro Nowoczesny generator

frontend

Astro - 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 strony
  • client: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 query
  • client: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.

Autor
MDS Software Solutions Group

Zespół ekspertów programistycznych specjalizujących się w nowoczesnych technologiach webowych.

Astro - Nowoczesny generator stron z architekturą Islands | MDS Software Solutions Group | MDS Software Solutions Group