# 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 ``` 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