07. Immagini, font, SEO, performance e deploy

← 06 - Rendering on-demand - adapter, middleware, actions · Indice · successivo → 08 - Reference rapida, errori comuni e migrazione

7.1 Immagini

---
import { Image, Picture } from 'astro:assets';
import foto from '../assets/foto.jpg';
---
<Image src={foto} alt="Descrizione della foto" />
<Picture src={foto} formats={['avif', 'webp']} alt="Descrizione" />

Cosa fa <Image /> che un <img> non fa: converte nel formato migliore, ridimensiona, aggiunge width/height (quindi niente layout shift), genera srcset quando serve, e mette in cache i risultati tra una build e l’altra.

alt è obbligatorio: senza, la build fallisce. È una scelta di design del framework, e giusta.

Immagini responsive: stabili dalla 5.10:

export default defineConfig({
  image: {
    layout: 'constrained',      // 'constrained' | 'fixed' | 'full-width'
    responsiveStyles: true,     // default false: senza, non sono responsive
  },
});

responsiveStyles è false di default

Imposti layout e ti aspetti immagini fluide; non succede niente. Ti serve anche responsiveStyles: true (a meno che gli stili te li scriva tu). Con Tailwind 4 invece lascialo false: i layer di Tailwind hanno specificità più bassa e verrebbero sovrascritti.

Immagini remote: per ottimizzarle devi autorizzarne l’origine, altrimenti vengono servite così come sono.

image: {
  domains: ['immagini.example.com'],
  remotePatterns: [{ protocol: 'https' }],
}

Nel Markdown la sintassi ![alt](./foto.jpg) funziona ed è ottimizzata per le immagini locali. Nei file .mdx puoi anche usare <Image /> direttamente.

Nelle collections, l’helper image() nello schema ti dà un ImageMetadata validato a partire da un path nel frontmatter (vedi 04 - Contenuti - Markdown, MDX e content collections).

Gli SVG importati diventano componenti Astro inline, con props width, height, fill, stroke, comodo per le icone, senza sprite né librerie.

Le immagini in public/ non vengono mai ottimizzate. È il motivo per cui una foto messa lì “perché era più veloce” pesa 4 MB in produzione.

📖 Images

7.2 Font

API integrata, stabile da Astro 6: scarica i font a build time, genera i fallback ottimizzati (riducono il layout shift) e gestisce il preload.

import { defineConfig, fontProviders } from 'astro/config';
 
export default defineConfig({
  fonts: [{
    provider: fontProviders.google(),
    name: 'Inter',
    cssVariable: '--font-inter',
    weights: [400, 600],
    subsets: ['latin'],
    fallbacks: ['sans-serif'],
  }],
});
---
import { Font } from 'astro:assets';   // NON da 'astro:fonts'
---
<head>
  <Font cssVariable="--font-inter" preload />
</head>
<style is:global>
  body { font-family: var(--font-inter), sans-serif; }
</style>

Provider disponibili: Google, Adobe, Bunny, Fontshare, Fontsource, Google Icons, NPM e local (per i tuoi file .woff2). Il vantaggio rispetto al <link> verso Google Fonts è che i file vengono serviti dal tuo dominio: meno round-trip, e nessuna richiesta a terzi.

📖 Fonts

7.3 SEO

Sitemap: richiede site configurato:

npx astro add sitemap

Genera sitemap-index.xml + sitemap-0.xml. Opzioni utili: filter (per escludere rotte), changefreq, lastmod, i18n.

robots.txt dinamico, come endpoint:

// src/pages/robots.txt.ts
import type { APIRoute } from 'astro';
 
export const GET: APIRoute = ({ site }) => {
  const sitemap = new URL('sitemap-index.xml', site);
  return new Response(`User-agent: *\nAllow: /\nSitemap: ${sitemap.href}\n`);
};

RSS:

// src/pages/rss.xml.js
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
 
export async function GET(context) {
  const post = await getCollection('blog');
  return rss({
    title: 'Il mio sito',
    description: 'Note e guide',
    site: context.site,
    items: post.map((p) => ({
      title: p.data.title,
      pubDate: p.data.pubDate,
      description: p.data.descrizione,
      link: `/blog/${p.id}/`,
    })),
  });
}

Poi l’autodiscovery nel layout:

<link rel="alternate" type="application/rss+xml" href={new URL('rss.xml', Astro.site)} />

URL canonico:

<link rel="canonical" href={new URL(Astro.url.pathname, Astro.site)} />

Tutto questo dipende dal campo site in astro.config.mjs. Senza, Astro.site è undefined e ti ritrovi con undefined/rss.xml in produzione.

7.4 Performance: cosa controllare davvero

Astro parte bene, ma non è immune. In ordine di impatto:

  1. Immagini: usa <Image />, non public/. È il primo posto dove si perdono secondi.
  2. Direttive client:*: ogni client:load è JavaScript nel percorso critico. Chiediti se client:visible basta. Quasi sempre basta.
  3. Font: usa la Fonts API con preload sul font del corpo testo, e nient’altro.
  4. Script di terze parti: analytics, chat, embed. Sono spesso il 90% del JavaScript di un sito Astro. @astrojs/partytown li sposta in un web worker.
  5. Prefetch: prefetch: true in config, o automatico con <ClientRouter />. Fa sembrare la navigazione istantanea a costo quasi zero.

Verifica sempre sulla build, non in dev: astro build && astro preview, poi Lighthouse. Il dev server ha caratteristiche di performance completamente diverse.

7.5 Build e deploy

astro build      # → dist/
astro preview    # serve dist/ localmente

Senza adapter: dist/ contiene HTML e asset, da caricare su qualunque hosting statico (GitHub Pages, Netlify, Cloudflare Pages, un VPS con nginx, S3).

Con adapter: dist/client/ (asset pubblici) e dist/server/ (il codice server, entry dist/server/entry.mjs).

Opzioni che tornano utili:

export default defineConfig({
  site: 'https://esempio.it',
  base: '/sottocartella',              // per GitHub Pages su repo non-root
  build: {
    format: 'directory',               // /pagina/index.html - default
    assets: '_astro',
    assetsPrefix: 'https://cdn.esempio.it',   // se servi gli asset da CDN
  },
});

Comandi nuovi in Astro 7 utili in CI o in locale:

  • astro dev --background + astro dev status | stop | logs [--follow]
  • astro dev --ignore-lock (7.1) per più dev server in parallelo
  • astro preview --background (7.2)
  • --json per log strutturati
  • astro build --force per svuotare la cache del content layer

Astro documenta oltre 30 piattaforme di deploy con guide dedicate: 📖 Deploy your site

Checklist prima di pubblicare

  • site impostato in astro.config.mjs
  • astro build senza warning
  • astro check pulito
  • 404 personalizzata presente e funzionante in preview
  • sitemap e RSS raggiungibili
  • <title> e <meta name="description"> diversi su ogni pagina
  • Lighthouse eseguito sulla build, non sul dev server
  • test su mobile reale, non solo nel simulatore

Esercizi

  1. Sostituisci tutti gli <img> di un tuo progetto con <Image /> e confronta il peso totale della pagina prima e dopo.
  2. Attiva la Fonts API con un font e verifica in Network che il .woff2 sia servito dal tuo dominio.
  3. Aggiungi sitemap + RSS + canonical, poi apri i file generati in dist/ e leggili.
  4. Fai girare Lighthouse su astro preview e scrivi le prime tre cose da migliorare.