[Lv2] Implementação SSR: Data Fetching e gestao de SEO Meta
Em um projeto Nuxt 3: implementar carregamento de dados em SSR e gestao dinâmica de SEO Meta para que buscadores indexem rotas dinâmicas corretamente.
1. Eixo da resposta na entrevista
- Estratégia de data fetching: usar
useFetch/useAsyncDatapara preload no servidor e entregar HTML completo para SEO. - Meta tags dinâmicas: usar
useHeadouuseSeoMetapara gerar metadata por recurso. - Performance: aplicar request deduplication, cache no servidor e separar claramente páginas SSR e CSR.
2. Uso correto de useFetch / useAsyncData
2.1 Por que data fetching em SSR é importante
Cenário típico:
- Rotas dinâmicas (ex.:
/products/[id]) precisam buscar dados de API. - Se carregar apenas no cliente, crawler pode ver conteúdo incompleto.
- Objetivo: entregar HTML renderizado no servidor com dados completos.
Solução: usar useFetch ou useAsyncData no Nuxt 3.
2.2 Exemplo base com useFetch
Arquivo: pages/products/[id].vue
// uso básico
const { data: product } = await useFetch(`/api/products/${route.params.id}`);
Op ções importantes:
| Opção | Objetivo | Default |
|---|---|---|
key | Chave única para deduplicar requests | auto |
lazy | Carga adiada (não bloqueia SSR) | false |
server | Executar no servidor | true |
default | Valor fallback | null |
transform | Transformar resposta antes do consumo | - |
2.3 Exemplo completo
// pages/products/[id].vue
const { data: product } = await useFetch(`/api/products/${route.params.id}`, {
key: `product-${route.params.id}`, // evita requests duplicados
lazy: false, // SSR espera os dados
server: true, // garante execucao no servidor
default: () => ({
id: null,
name: '',
description: '',
image: '',
}),
transform: (data: any) => {
// normalização de dados
return {
...data,
formattedPrice: formatPrice(data.price),
};
},
});
Por que essas opções importam:
key- Permite request deduplication.
- Mesmo key -> um request efetivo.
lazy: false- Servidor renderiza depois de receber dados.
- Crawler recebe conteúdo final.
server: true- Fetch roda no caminho SSR.
- Evita depender somente do cliente.
2.4 useAsyncData vs useFetch
| Criterio | useFetch | useAsyncData |
|---|---|---|
| Uso principal | Chamada API | Qualquer operação assíncrona |
| Conveniencia | URL/header integrados | Logica manual |
| Caso comum | HTTP data fetching | Query de DB, agregacao, arquivos |
// useFetch: focado em API
const { data } = await useFetch('/api/products/123');
// useAsyncData: lógica async livre
const { data } = await useAsyncData('products', async () => {
const result = await someAsyncOperation();
return result;
});
2.5 $fetch vs useFetch
Regra curta para entrevista:
$fetchpara ação do usuário (click, submit, refresh).useFetchpara carga inicial com sincronização SSR/Hydration.
$fetch características:
- Cliente HTTP puro (
ofetch) - Não transfere estado SSR
- Uso direto em
setup()pode gerar double fetch
useFetch características:
- Combina
useAsyncData+$fetch - Amigavel para hydration
- Entrega
data,pending,error,refresh
Comparação:
| Ponto | useFetch | $fetch |
|---|---|---|
| Transferencia SSR | Sim | Não |
| Retorno | Refs reativas | Promise com dados brutos |
| Uso principal | Carga inicial da página | Operacoes dirigidas por evento |
// correto: carga inicial
const { data } = await useFetch('/api/user');
// correto: ação de usuário
const submitForm = async () => {
await $fetch('/api/submit', { method: 'POST', body: form });
};
// evitar: setup + $fetch direto
const data = await $fetch('/api/user');
3. Gestao de SEO Meta com useHead
3.1 Por que meta tags dinâmicas são necessárias
Cenário típico:
- Páginas de produto e artigo são dinâmicas.
- Cada URL precisa de
title,description,og:image, canonical próprios. - Compartilhamento social (Open Graph/Twitter) precisa ser consistente.
Solução: useHead ou useSeoMeta.
3.2 Exemplo de useHead
useHead({
title: () => product.value?.name,
meta: [
{ name: 'description', content: () => product.value?.description },
{ property: 'og:title', content: () => product.value?.name },
{ property: 'og:image', content: () => product.value?.image },
],
link: [
{
rel: 'canonical',
href: () => `https://example.com/products/${product.value?.id}`,
},
],
});
Boas práticas:
- Passar valores como função (
() => ...) para reagir a mudancas de dados. - Cobrir estrutura SEO completa: title, description, OG, canonical.
- Em 404, usar
noindex, nofollow.
3.3 Variante compacta com useSeoMeta
useSeoMeta({
title: () => product.value?.name,
description: () => product.value?.description,
ogTitle: () => product.value?.name,
ogDescription: () => product.value?.description,
ogImage: () => product.value?.image,
});
4. Caso prático 1: SEO para rotas dinâmicas
4.1 Contexto
Cenário de e-commerce com muitas páginas SKU (/products/[id]).
Desafios:
- Muitas URLs dinâmicas
- SEO único por URL
- Tratamento correto de 404
- Evitar conteúdo duplicado
4.2 Estratégia
- Preload no servidor (
lazy: false,server: true) - Lancar 404 com
createError - Gerar meta e canonical dinamicamente
const { data: product, error } = await useFetch(`/api/products/${id}`, {
key: `product-${id}`,
lazy: false,
server: true,
});
if (error.value || !product.value) {
throw createError({ statusCode: 404, statusMessage: 'Product not found' });
}
useSeoMeta({
title: () => `${product.value?.name} - Product`,
description: () => product.value?.description,
ogTitle: () => product.value?.name,
ogDescription: () => product.value?.description,
ogImage: () => product.value?.image,
});
4.3 Resultado
Antes:
- Crawler via conteúdo incompleto
- Varias páginas com metadata repetida
- 404 inconsistente
Depois:
- HTML SSR completo para crawler
- Metadata único por rota
- Tratamento de erro consistente é seguro para SEO
5. Caso prático 2: Otimização de performance
5.1 Problema
SSR aumenta carga de servidor. Sem otimização, latencia e custo sobem.
5.2 Estratégias
- Request deduplication
const { data } = await useFetch('/api/product/123', {
key: 'product-123',
});
- Cache em servidor (Nitro)
export default defineCachedEventHandler(
async (event) => {
return await getProductsFromDB();
},
{
maxAge: 60 * 60,
swr: true,
},
);
- Separar SSR/CSR
- Páginas críticas para SEO: SSR
- Páginas internas sem indexação: CSR
- Critical CSS e estratégia de assets
- Priorizar CSS above-the-fold
- Carregar recursos não críticos depois
5.3 Impacto
Antes:
- Alta carga no servidor
- Requests duplicados
- Sem estratégia de cache
Depois:
- Melhor tempo de resposta
- Menos pressao em backend/DB
- Performance mais estável sob carga
6. Respostas curtas de entrevista
6.1 useFetch / useAsyncData
Na carga inicial eu uso
useFetchcomkey,lazy: falseeserver: truepara garantir SSR completo e HTML útil para indexação.
6.2 Meta tags dinâmicas
Eu uso
useHead/useSeoMetacom valores em função para atualizar metadados conforme os dados, incluindo OG e canonical.
6.3 Performance
Eu combino deduplication, cache no servidor e split SSR/CSR para reduzir TTFB sem perder qualidade de SEO.
7. Best practices
7.1 Data fetching
- Definir
keysempre. - Escolher
lazyde acordo com objetivo SEO. - Tratar erros (404/5xx) explicitamente.
7.2 SEO Meta
- Valores funcionais para updates reativos.
- Estrutura completa (title/description/OG/canonical).
- Proteger páginas de erro com
noindex, nofollow.
7.3 Performance
- Aplicar cache no servidor.
- Usar SSR apenas onde SEO precisa.
- Reduzir custo de render com estratégia de CSS/assets.
8. Resumo para entrevista
Em Nuxt 3 eu implementei data fetching SSR e gestao dinâmica de SEO Meta para cobrir dois objetivos: indexação correta e experiência rápida. Para isso eu combinei preload no servidor, metadados por rota e otimizações com deduplication, cache e separação SSR/CSR.
Pontos-chave:
- ✅ Uso correto de
useFetch/useAsyncData - ✅ Gestao dinâmica com
useHead/useSeoMeta - ✅ SEO para rotas dinâmicas
- ✅ Performance em cenários reais