# Nuxt 3: SSR e generazione statica, la guida completa
> Padroneggiare SSR e generazione statica con Nuxt 3. Da useFetch alle route rules, scoprire come ottimizzare le prestazioni delle applicazioni Vue.js.
- Published: 2026-02-11
- Updated: 2026-04-28
- Author: SharpSkill
- Tags: nuxt 3, vue.js, ssr, generazione statica, performance web
- Reading time: 12 min
---
Nuxt 3 trasforma il modo in cui vengono costruite le applicazioni Vue.js, offrendo molteplici modalità di rendering adatte a casi d'uso diversi. Dal Server-Side Rendering (SSR) alla generazione statica fino al rendering ibrido, il framework offre una flessibilità notevole per ottimizzare prestazioni e SEO.
> **Prerequisiti**
>
> Questo tutorial presuppone una conoscenza di base di Vue 3 e della Composition API. La familiarità con i concetti di rendering lato server è utile ma non obbligatoria, poiché i fondamentali vengono spiegati lungo tutta la guida.
## Comprendere le modalità di rendering di Nuxt 3
Prima di immergersi nel codice, è essenziale comprendere le differenze tra le modalità di rendering disponibili. Ogni modalità risponde a esigenze specifiche in termini di prestazioni, SEO ed esperienza utente.
Il SSR (Server-Side Rendering) genera l'HTML sul server a ogni richiesta. La generazione statica (SSG) pre-genera tutte le pagine al momento del build. La modalità ibrida consente di combinare questi approcci pagina per pagina.
```typescript
// nuxt.config.ts
// Configurazione delle diverse modalità di rendering
export default defineNuxtConfig({
// SSR attivo per default (consigliato per la SEO)
ssr: true,
// Generazione statica: pre-renderizza tutte le pagine
// Usare 'npm run generate' per il build
// target: 'static', // Sintassi Nuxt 2
// Modalità ibrida: configurabile per rotta
routeRules: {
// Home page: pre-renderizzata e in cache
'/': { prerender: true },
// Blog: generazione statica
'/blog/**': { prerender: true },
// Dashboard: rendering solo lato client
'/dashboard/**': { ssr: false },
// API: nessun pre-rendering
'/api/**': { prerender: false }
}
})
```
Questa configurazione mostra la potenza della modalità ibrida: ogni sezione dell'applicazione utilizza la modalità di rendering più adatta alle proprie esigenze.
## Recupero dei dati con useFetch e useAsyncData
Nuxt 3 fornisce due composable principali per recuperare i dati in modo isomorfo. Questi composable funzionano sia lato server sia lato client, con una gestione automatica dell'idratazione.
`useFetch` è un wrapper attorno a `useAsyncData` che semplifica le chiamate HTTP. `useAsyncData` offre più controllo per casi d'uso avanzati.
```vue
Caricamento articolo...
{{ article.title }}
```
Per i casi che richiedono più controllo, `useAsyncData` consente di eseguire qualsiasi funzione asincrona.
```vue
```
Questi composable evitano il doppio fetching: i dati recuperati sul server vengono serializzati nel payload HTML e riutilizzati durante l'idratazione lato client.
## Personalizzare l'SSR con i server hooks
L'SSR di Nuxt 3 può essere personalizzato tramite i server hooks. Questi hooks consentono di intervenire in diverse fasi del ciclo di rendering per modificare il comportamento di default.
```typescript
// server/plugins/render-hooks.ts
// Plugin di server per personalizzare il rendering SSR
export default defineNitroPlugin((nitroApp) => {
// Hook eseguito prima del rendering di ogni pagina
nitroApp.hooks.hook('render:html', (html, { event }) => {
// Iniettare script o metadati
html.head.push(`
`)
})
// Hook per la gestione della cache di rendering
nitroApp.hooks.hook('render:response', (response, { event }) => {
// Aggiungere header di cache personalizzati
const path = event.path
if (path.startsWith('/blog/')) {
// Cache lunga per gli articoli del blog
response.headers['Cache-Control'] = 'public, max-age=3600, s-maxage=86400'
} else if (path.startsWith('/api/')) {
// Nessuna cache per le API
response.headers['Cache-Control'] = 'no-store'
}
})
})
```
> **Prestazioni dell'SSR**
>
> L'hook `render:response` è ideale per implementare strategie di cache HTTP. Combinare l'SSR con un CDN che rispetti gli header Cache-Control consente di servire pagine pre-renderizzate mantenendo la possibilità di invalidarle.
## Generazione statica con nuxt generate
La generazione statica costruisce in anticipo tutte le pagine al momento del build. Questo approccio è ideale per siti con contenuto stabile come blog, documentazione o siti di marketing.
Per le rotte dinamiche, Nuxt deve conoscere tutti gli URL da generare. L'hook `prerender:routes` consente di definire queste rotte in modo programmatico.
```typescript
// nuxt.config.ts
// Configurazione completa per la generazione statica
export default defineNuxtConfig({
// Attivare la generazione statica
nitro: {
prerender: {
// Attivare il crawling automatico dei link
crawlLinks: true,
// Rotte da includere sempre
routes: ['/', '/about', '/contact'],
// Ignorare alcune rotte
ignore: ['/admin', '/api']
}
},
hooks: {
// Hook per generare rotte dinamiche
async 'prerender:routes'(ctx) {
// Recuperare gli articoli da API o DB
const articles = await fetch('https://api.example.com/articles')
.then(res => res.json())
// Aggiungere le rotte degli articoli
for (const article of articles) {
ctx.routes.add(`/blog/${article.slug}`)
}
// Recuperare le categorie
const categories = await fetch('https://api.example.com/categories')
.then(res => res.json())
for (const category of categories) {
ctx.routes.add(`/category/${category.slug}`)
}
}
}
})
```
Per progetti con molte pagine, il crawler automatico può risultare insufficiente. Ecco un approccio più robusto con un file di configurazione separato.
```typescript
// server/utils/generate-routes.ts
// Utility per generare la lista delle rotte dinamiche
import { prisma } from './prisma'
export async function getAllStaticRoutes(): Promise {
const routes: string[] = []
// Articoli del blog
const articles = await prisma.article.findMany({
where: { published: true },
select: { slug: true, category: { select: { slug: true } } }
})
for (const article of articles) {
routes.push(`/blog/${article.category.slug}/${article.slug}`)
}
// Pagine prodotto
const products = await prisma.product.findMany({
where: { active: true },
select: { slug: true }
})
for (const product of products) {
routes.push(`/products/${product.slug}`)
}
// Pagine tag
const tags = await prisma.tag.findMany({
select: { slug: true }
})
for (const tag of tags) {
routes.push(`/tags/${tag.slug}`)
}
return routes
}
```
## Rendering ibrido con routeRules
Il rendering ibrido è la funzione di punta di Nuxt 3. Consente di definire regole di rendering diverse per ciascuna rotta, combinando il meglio di SSR e SSG.
```typescript
// nuxt.config.ts
// Configurazione avanzata del rendering ibrido
export default defineNuxtConfig({
routeRules: {
// Pagine marketing: pre-renderizzate e in cache a lungo termine
'/': { prerender: true },
'/pricing': { prerender: true },
'/features/**': { prerender: true },
// Blog: ISR (Incremental Static Regeneration)
// Revalidazione ogni ora
'/blog/**': {
isr: 3600,
prerender: true
},
// Documentazione: cache CDN con revalidazione
'/docs/**': {
swr: 86400, // Stale-while-revalidate
prerender: true
},
// E-commerce: SSR con cache breve
'/products/**': {
ssr: true,
cache: {
maxAge: 60,
staleMaxAge: 300
}
},
// Carrello e checkout: solo lato client
'/cart': { ssr: false },
'/checkout/**': { ssr: false },
// Dashboard: modalità SPA
'/dashboard/**': {
ssr: false,
// Disattivare il pre-rendering
prerender: false
},
// Rotte API: nessuna cache di default
'/api/**': {
cors: true,
headers: {
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE'
}
}
}
})
```
Questa configurazione illustra un'architettura tipica delle applicazioni moderne: le pagine pubbliche sono ottimizzate per la SEO con SSG, mentre le sezioni interattive utilizzano il rendering lato client.
## Ottimizzazione delle prestazioni con la cache dei dati
Oltre alla cache delle pagine, Nuxt 3 consente di mettere in cache i dati recuperati. Questa strategia riduce il carico sulle API e migliora i tempi di risposta.
```typescript
// server/api/articles/[slug].get.ts
// Endpoint API con cache dei dati
import { getArticleBySlug } from '~/server/utils/articles'
export default defineCachedEventHandler(
async (event) => {
const slug = getRouterParam(event, 'slug')
if (!slug) {
throw createError({
statusCode: 400,
message: 'Slug mancante'
})
}
const article = await getArticleBySlug(slug)
if (!article) {
throw createError({
statusCode: 404,
message: 'Articolo non trovato'
})
}
return article
},
{
// Chiave di cache basata sullo slug
getKey: (event) => `article-${getRouterParam(event, 'slug')}`,
// Durata della cache: 1 ora
maxAge: 3600,
// Stale-while-revalidate: servire la cache obsoleta durante l'aggiornamento
staleMaxAge: 7200,
// Invalidazione basata su tag
tags: ['articles']
}
)
```
Per invalidare la cache quando i contenuti cambiano, Nuxt fornisce un sistema di tag.
```typescript
// server/api/articles/[slug].put.ts
// Aggiornamento articolo con invalidazione della cache
import { updateArticle } from '~/server/utils/articles'
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, 'slug')
const body = await readBody(event)
// Aggiornare l'articolo
const article = await updateArticle(slug, body)
// Invalidare la cache per questo articolo
await useStorage('cache').removeItem(`nitro:handlers:article-${slug}`)
// Oppure invalidazione basata sui tag (tutti gli articoli)
// await useStorage('cache').clear('articles')
return article
})
```
> **Cache distribuita**
>
> In produzione con più istanze, la cache in memoria è insufficiente. Si consiglia di configurare Redis o un altro sistema distribuito tramite la configurazione di Nitro per garantire la coerenza tra le istanze.
## Gestione di SEO e metadati
L'SSR consente di ottimizzare la SEO generando i metadati lato server. Nuxt 3 propone diversi approcci per gestire i meta tag in modo dinamico.
```vue
```
Per le pagine statiche, i metadati possono essere definiti direttamente nel componente.
```vue
```
## Deploy e considerazioni di produzione
La scelta del deploy dipende dalla modalità di rendering utilizzata. Ecco le opzioni principali e le loro configurazioni.
```typescript
// nuxt.config.ts
// Configurazione per diversi ambienti di deploy
export default defineNuxtConfig({
nitro: {
// Preset in base alla piattaforma di destinazione
// preset: 'vercel', // Vercel
// preset: 'netlify', // Netlify
// preset: 'cloudflare-pages', // Cloudflare
// preset: 'node-server', // Node.js classico
// Configurazione per Node.js in produzione
preset: 'node-server',
// Compressione delle risposte
compressPublicAssets: true,
// Configurazione dello storage di cache
storage: {
cache: {
driver: 'redis',
url: process.env.REDIS_URL
}
}
},
// Variabili d'ambiente runtime
runtimeConfig: {
// Segreti (non esposti al client)
apiSecret: process.env.API_SECRET,
// Configurazione pubblica
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
}
}
})
```
Per il deploy statico, il comando `npm run generate` crea una cartella `.output/public` pronta per essere distribuita su qualsiasi host di file statici.
```bash
# Generazione statica
npm run generate
# Il contenuto di .output/public può essere distribuito su:
# - Vercel (rilevamento automatico)
# - Netlify (configurazione automatica)
# - GitHub Pages
# - S3 + CloudFront
# - Qualsiasi CDN o server di file statici
```
## Conclusione
Nuxt 3 offre una flessibilità eccezionale per il rendering delle applicazioni Vue.js. La scelta tra SSR, SSG e rendering ibrido dipende dalle esigenze specifiche di ciascun progetto.
**Punti chiave:**
✅ **SSR**: ideale per contenuti dinamici che richiedono buona SEO (e-commerce, siti di notizie)
✅ **SSG**: perfetto per contenuti stabili (blog, documentazione, siti di marketing)
✅ **Ibrido**: l'approccio migliore per applicazioni complesse con esigenze variegate
✅ **useFetch/useAsyncData**: idratazione automatica e gestione della cache
✅ **routeRules**: configurazione granulare per il comportamento di ogni rotta
✅ **Caching**: molteplici strategie per ottimizzare le prestazioni in produzione
Combinare il rendering ibrido con una strategia di cache ben pensata consente di costruire applicazioni performanti e ottimizzate per la SEO, mantenendo l'interattività delle Single Page Applications.
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/it/blog/vue-nuxt/nuxt-3-ssr-static-generation