Capítulo 17: Framework Nuxt 3 (Universal Rendering e File-based Routing)
Capítulo 17: Framework Nuxt 3 (Universal Rendering e File-based Routing)
Especialização em Front-End com Vue • Vue 3 & Nuxt 3 • Composition API, Pinia, Vue Router, SSR e TypeScript
🗺️ Mapa Conceitual do Framework Nuxt 3
flowchart TD
A["Requisição do Navegador / Cliente"] --> B["Servidor Nitro Engine (H3 + Node/Edge)"]
subgraph SSR_PIPELINE["Pipeline de Renderização Universal (SSR)"]
C["1. Execução de Server Middleware"]
D["2. Resolução de Rota Baseada em Arquivos (pages/)"]
E["3. Execução de useAsyncData / $fetch no Servidor"]
F["4. Serialização do Estado em window.__NUXT__"]
G["5. Envio do HTML Pré-Renderizado para o Cliente"]
end
B --> SSR_PIPELINE
G --> H["Navegador do Usuário: Exibição Imediata (First Paint)"]
H --> I["Hidratação do Vue 3: Ativação dos Eventos Reativos no Cliente"]
style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style SSR_PIPELINE fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style I fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
🏛️ 1. A Revolução do Nuxt 3: SSR, Nitro e Convenções
O Nuxt 3 é o framework full-stack oficial de maior prestígio construído sobre o Vue 3. Ele combina o poder do Vite para compilação client-side ultra-rápida com o novo motor de servidor Nitro Engine, viabilizando renderização isomórfica em qualquer plataforma de nuvem (Node.js, AWS Lambda, Cloudflare Workers, Vercel ou Netlify).
1.1 Universal Rendering (SSR) e Hidratação Isomórfica
No modelo clássico de SPA pura (Vite client-side), o servidor entrega um arquivo HTML praticamente vazio (<div id="app"></div>) e o navegador precisa baixar e executar todo o JavaScript para que o usuário veja a página.
No Nuxt 3 com Universal Rendering:
- O servidor (Nitro) executa os componentes Vue e as chamadas assíncronas de dados, enviando ao navegador o HTML completo e totalmente preenchido.
- O usuário enxerga o conteúdo imediatamente (minimizando o FCP - First Contentful Paint e otimizando o SEO).
- O JavaScript do cliente é carregado em segundo plano e realiza a Hidratação (Hydration): anexa ouvintes de eventos e reatividade ao HTML estático sem piscar ou recriar a tela.
1.2 Roteamento Baseado em Arquivos (pages/)
O Nuxt analisa a árvore de diretórios dentro de pages/ e gera automaticamente a tabela de rotas do Vue Router:
pages/index.vue➔/pages/projetos/index.vue➔/projetospages/projetos/[id].vue➔/projetos/:id(Rotas Dinâmicas)pages/[...slug].vue➔ Rotas Catch-All (ex: 404 customizado)
1.3 Sistema de Auto-Imports
No Nuxt 3, você não precisa declarar dezenas de imports manuais no topo dos arquivos .vue:
- Todas as funções da Composition API (
ref,computed,watch,onMounted) são auto-importadas. - Todos os composables customizados criados na pasta
composables/são auto-importados. - Todos os componentes criados na pasta
components/são auto-importados com suporte a lazy-loading automático (<LazyCard />).
1.4 Consumo Universal de Dados: useAsyncData e useFetch
Para evitar o problema crônico de Double Fetching (onde o servidor faz a requisição e o cliente faz a mesma requisição novamente após a hidratação):
// Executa no servidor e injeta o resultado no payload serializado
const { data, pending, error } = await useFetch('/api/usuarios');
⚖️ 2. Tabela Comparativa: Vite SPA Pura vs Nuxt 3
| Critério Arquitetural | Vite SPA Pura | Nuxt 3 (Universal Framework) |
|---|---|---|
| SEO e Indexação de Buscadores | Baixo a Nulo sem pré-renderização externa. | Perfeito (HTML entregue pré-renderizado). |
| Primeira Pintura (FCP) | Lenta (aguarda download de todo o bundle JS). | Instantânea (HTML puro recebido de imediato). |
| Configuração de Rotas | Manual em router/index.ts. |
Automática baseada em arquivos (pages/). |
| Motor de Backend Embutido | Inexistente (requer backend externo separado). | Nativo com Nitro (server/api/). |
| Complexidade de Deploy | Simples (qualquer CDN ou S3). | Simples a Média (Node server, Serverless ou Edge). |
⚠️ 3. Armadilhas Comuns em Produção (Gotchas & Anti-Patterns)
Anti-Pattern 1: Erros de Hydration Mismatch
Erro Comum: Escrever código no template que renderiza valores diferentes no servidor e no cliente, como exibir a data corrente (new Date().toLocaleTimeString()) ou conferir window.innerWidth.
Consequência: O console exibirá o aviso [Hydration mismatch], forçando o Vue a descartar o HTML do servidor e re-renderizar todo o nó no cliente, degradando a performance.
Abordagem Correta: Utilize <ClientOnly> para envolver partes da interface que só fazem sentido no navegador do usuário.
Anti-Pattern 2: Usar fetch() Nativo sem useAsyncData
Erro Comum: Chamar fetch('...') solto em <script setup>. O servidor executará a requisição e, logo em seguida, o navegador executará exatamente a mesma requisição no cliente, dobrando a carga sobre a API.
💻 4. Código Conceitual Arquitetural Comentado
<!-- pages/cluster/[id].vue -->
<script setup lang="ts">
// Nuxt 3 auto-importa useRoute, useAsyncData, useHead
const route = useRoute();
const clusterId = route.params.id as string;
interface ClusterInfo {
id: string;
name: string;
region: string;
nodesOnline: number;
}
// useAsyncData previne refetch no cliente reaproveitando o payload serializado
const { data: cluster, pending, error } = await useAsyncData<ClusterInfo>(
`cluster-detail-${clusterId}`,
() => $fetch(`/api/clusters/${clusterId}`)
);
// Injeção dinâmica de metadados para motores de busca e crawlers
useHead({
title: () => `${cluster.value?.name ?? 'Cluster'} | Nuxt Enterprise`,
meta: [
{ name: 'description', content: `Painel de telemetria do cluster ${clusterId}` }
]
});
</script>
<template>
<div class="max-w-2xl mx-auto p-6 space-y-4">
<div v-if="pending" class="p-6 bg-slate-50 border rounded-xl text-center text-xs text-slate-400">
Carregando detalhes do cluster via SSR...
</div>
<div v-else-if="cluster" class="bg-white border rounded-2xl p-6 shadow-sm space-y-3">
<div class="flex justify-between items-center">
<h2 class="text-xl font-black text-slate-800">{{ cluster.name }}</h2>
<span class="text-xs px-2.5 py-1 bg-emerald-100 text-emerald-800 rounded-full font-bold">
{{ cluster.region }}
</span>
</div>
<p class="text-xs text-slate-500 font-mono">ID do Cluster: {{ cluster.id }}</p>
<div class="text-lg font-bold text-indigo-600">
{{ cluster.nodesOnline }} nós operacionais
</div>
</div>
</div>
</template>
🛠️ 5. Cheat-Sheet de Diretórios Canônicos do Nuxt 3
meu-projeto-nuxt/
├── server/ # Rotas de API backend com Nitro (server/api/...)
├── pages/ # Rotas baseadas em arquivos (geram Vue Router)
├── layouts/ # Layouts reutilizáveis (default.vue, admin.vue)
├── components/ # Componentes com auto-import e prefixo de pasta
├── composables/ # Funções de lógica de estado com auto-import
├── stores/ # Stores globais do Pinia
├── public/ # Arquivos estáticos servidos na raiz (favicon, robots.txt)
└── nuxt.config.ts # Arquivo de configuração central do Nuxt