Capítulo 18: Server Routes, Server-Side Rendering (SSR) e SSG no Nuxt
Capítulo 18: Server Routes, Server-Side Rendering (SSR) e SSG no Nuxt
Especialização em Front-End com Vue • Vue 3 & Nuxt 3 • Composition API, Pinia, Vue Router, SSR e TypeScript
🗺️ Mapa Conceitual do Nitro Engine e Renderização Híbrida
flowchart TD
A["Requisição HTTP Entrante"] --> B["Nitro Engine (H3 Event Handler)"]
B --> C{"Tipo de Destino"}
C -->|"Rota de API Backend: server/api/*"| D["defineEventHandler() -> Resposta JSON"]
C -->|"Página Frontend: pages/*"| E{"Regra em routeRules (nuxt.config)"}
E -->|"prerender: true"| F["SSG (HTML Estático no Build)"]
E -->|"ssr: true (Padrão)"| G["SSR Dinâmico sob Demanda"]
E -->|"swr: 60"| H["SWR Cache no Edge / CDN"]
E -->|"ssr: false"| I["SPA Puro no Navegador"]
D & F & G & H & I --> J["Entrega Otimizada ao Cliente"]
style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style D fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style E fill:#fff9c4,stroke:#fbc02d,stroke-width:2px
style J fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
🏛️ 1. O Nitro Engine e a Renderização Híbrida
No Nuxt 3, o backend não é um servidor Node.js pesado e separado; ele é provido nativamente pelo Nitro Engine, um servidor web leve e ultra-otimizado baseado no framework minimalista H3. Com o Nitro, você pode construir rotas de API tipadas, manipular webhooks, conectar diretamente a bancos de dados com Prisma ou Drizzle e definir regras de renderização cirúrgicas por rota através de routeRules.
1.1 Rotas de Servidor: server/api/ e defineEventHandler
Qualquer arquivo dentro do diretório server/api/ torna-se automaticamente um endpoint HTTP REST:
server/api/relatorio.get.tsresponde exclusivamente a requisições HTTPGET /api/relatorio.server/api/usuario.post.tsresponde a requisições HTTPPOST /api/usuario.- Os manipuladores são definidos através de
defineEventHandler(async (event) => { ... }), com acesso a funções utilitárias do H3:getQuery(event): Faz o parse seguro de parâmetros de query string.readBody(event): Lê e valida o payload JSON enviado no corpo do POST/PUT.createError({ statusCode, statusMessage }): Dispara erros HTTP formatados.
1.2 Segurança e Proteção de Segredos com runtimeConfig
O maior risco de segurança em aplicações front-end é vazar tokens privados de banco de dados ou chaves de IA (como OpenAI/Anthropic API keys) no código do cliente. No Nuxt 3:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
// Chaves privadas (Acessíveis APENAS em server/):
databasePassword: process.env.DB_PASSWORD,
// Chaves públicas (Acessíveis tanto no cliente quanto no servidor):
public: {
apiBaseUrl: 'https://api.empresa.com.br'
}
}
});
1.3 As 4 Modalidades de Renderização Híbrida (routeRules)
Você não precisa escolher entre SPA, SSR ou SSG para todo o projeto. O Nuxt permite misturar as 4 estratégias no mesmo arquivo de configuração:
- SSG (Static Site Generation):
{ prerender: true }. A página é compilada em HTML estático durante a esteira de CI/CD. Ideal para blogs, documentação e páginas institucionais. - SSR (Server-Side Rendering):
{ ssr: true }. A página é gerada no servidor a cada requisição. Ideal para e-commerce e portais de notícias. - SWR (Stale-While-Revalidate):
{ swr: 60 }. O servidor atende a requisição a partir do cache da CDN e, em segundo plano, revalida o conteúdo a cada 60 segundos. - SPA (Single Page Application):
{ ssr: false }. Desabilita o SSR, entregando apenas a casca do app. Ideal para painéis administrativos fechados sob login.
⚖️ 2. Tabela Comparativa de Estratégias de Renderização
| Modo | Geração do HTML | Custo de Servidor | Latência (TTFB) | Ideal Para |
|---|---|---|---|---|
| SSG | No build time (CI/CD). | Praticamente zero (CDN estática). | Ultra-Baixa (< 50ms). | Páginas de Marketing, Documentações. |
| SSR | A cada requisição no servidor. | Moderado (requer computação Node/Edge). | Média (depende do banco de dados). | E-commerces, Portais de Notícias dinâmicos. |
| SWR | Cache na CDN com revalidação. | Baixo (computa apenas a cada intervalo). | Ultra-Baixa (servido do cache). | Catálogos de produtos de alto tráfego. |
| SPA | No navegador do cliente. | Zero no servidor (apenas arquivos estáticos). | Lenta na primeira carga; rápida após. | Dashboards corporativos fechados. |
⚠️ 3. Armadilhas Comuns em Produção (Gotchas & Anti-Patterns)
Anti-Pattern 1: Acessar Segredos de Servidor dentro de Componentes Vue
Erro Comum: Escrever const config = useRuntimeConfig(); console.log(config.databasePassword) dentro de um componente .vue.
Consequência: O valor retornará undefined no cliente, e se renderizado durante o SSR, o segredo poderá ser vazado no HTML enviado ao navegador.
Regra de Ouro: Chaves de API privadas e senhas devem residir exclusivamente dentro de server/api/.
Anti-Pattern 2: Esquecer de Definir o Método HTTP no Nome do Arquivo
Erro Comum: Criar server/api/orders.ts para salvar pedidos. Sem o sufixo .post.ts, a rota responderá a qualquer método HTTP (GET, DELETE, etc.), violando boas práticas REST.
💻 4. Código Conceitual Arquitetural Comentado
// server/api/system/audit.post.ts
import { defineEventHandler, readBody, createError } from 'h3';
interface AuditLogPayload {
userId: string;
action: string;
entityId: string;
}
export default defineEventHandler(async (event) => {
// 1. Acesso seguro a segredos do servidor
const config = useRuntimeConfig();
// 2. Leitura e validação de payload tipado
const body = await readBody<AuditLogPayload>(event);
if (!body.userId || !body.action) {
throw createError({
statusCode: 400,
statusMessage: 'Requisição inválida: userId e action são campos obrigatórios.'
});
}
// 3. Simulação de inserção segura no banco de dados da infraestrutura
const logRecord = {
id: `log-${Date.now()}`,
...body,
createdAt: new Date().toISOString()
};
console.log('[Nitro Database] Auditoria registrada com sucesso:', logRecord);
return { success: true, record: logRecord };
});
🛠️ 5. Cheat-Sheet de Configuração do routeRules
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 1. Pré-renderizar páginas estáticas (SSG)
'/institucional/**': { prerender: true },
// 2. Cache na CDN com revalidação de 10 minutos (SWR)
'/produtos/**': { swr: 600 },
// 3. SPA puro para o painel administrativo (Zero SSR)
'/admin/**': { ssr: false },
// 4. Redirecionamento 301 definitivo
'/legado-portal': { redirect: { to: '/novo-portal', statusCode: 301 } }
}
});