404 Not Found

404 Not Found


nginx

Otimização SEO: useHead + useSeoMeta

O MegaShop do Charlie tem um milhão de páginas de produtos, mas o Google indexou apenas 2.000 delas. Quando Alice busca pelo nome de um produto, ela não consegue encontrar nenhuma página do MegaShop. Bob verificou e descobriu que as páginas de produtos carecem de títulos, meta descriptions, tags Open Graph e dados estruturados. O toolchain SEO do Nuxt 3 pode resolver todos esses problemas.

1. O Que Você Vai Aprender


2. Uma História Real de um Arquiteto

(1) Ponto Crítico: De um milhão de páginas, apenas 2.000 são indexadas pelo Google

Charlie verificou o MegaShop usando o Google Search Console e descobriu que de 1 milhão de páginas de produtos, apenas 2.000 haviam sido indexadas. A análise de Bob revelou que todas as páginas de produtos tinham o título "MegaShop," meta descriptions vazias e tags Open Graph ausentes — o que significava que, quando compartilhadas nas redes sociais, apenas o nome do site aparecia, sem informações do produto.

(2) Solução com o Toolchain SEO do Nuxt

O useHead e useSeoMeta do Nuxt 3 permitem que cada página de produto tenha seus próprios metadados SEO:

TYPESCRIPT
// pages/products/[id].vue
useSeoMeta({
  title: product.value?.name,
  ogTitle: product.value?.name,
  description: `Buy ${product.value?.name} for $${product.value?.price} USD`,
  ogImage: product.value?.image
})

(3) Resultados: Taxa de indexação do Google disparou 40 vezes

Após três meses, o índice do Google saltou de 2.000 para 800.000, e o tráfego de busca orgânica aumentou 340%.


3. Arquitetura do Toolchain SEO

(1) Visão Geral do Toolchain SEO do Nuxt 3

100%
graph TB
    A[Nuxt SEO Toolkit] --> B[useHead]
    A --> C[useSeoMeta]
    A --> D[JSON-LD]
    A --> E[@nuxtjs/sitemap]
    A --> F[robots.txt]
    B --> B1[title / meta / link]
    C --> C1[OG / Twitter Card]
    D --> D1[Product / Breadcrumb]
    E --> E1[Dynamic URL Generation]
    F --> F1[Crawler Access Control]
    ```
    
---

## 4. Gerenciamento Dinâmico com useHead

### (1) O que o useHead pode gerenciar?

| Tipo de Tag | Atributo | Impacto SEO |
|:---------|:-----|:---------|
| title | Título da Página | 🔴 Alto (Sinal de Ranking) |
| meta name="description" | Descrição da Página | 🔴 Alto (Taxa de cliques) |
| meta property="og:*" | Open Graph | 🟡 Médio (Compartilhamento Social) |
| meta name="twitter:*" | Twitter Card | 🟡 Médio (Compartilhamento Social) |
| link rel="canonical" | URL Canônica | 🔴 Alto (desduplicação) |
| link rel="alternate" | URL Multilíngue | 🟡 Médio (i18n SEO) |
| script type="application/ld+json" | JSON-LD | 🟡 Suportado (Rich Snippets) |

### (1) ▶Exemplo: Uso Básico do useHead

```typescript
// Em qualquer componente ou página
useHead({
  title: 'Premium Headphones - MegaShop',
  meta: [
    { name: 'description', content: 'Buy Premium Headphones for $299.99 USD. Free shipping.' },
    { name: 'keywords', content: 'headphones, wireless, premium, audio' }
  ],
  link: [
    { rel: 'canonical', href: 'https://megashop.com/products/123' }
  ]
})

Saída:

TEXT
// Execução Bem-sucedida

(2) ▶Exemplo: Título dinâmico (computed, reativo)

VUE
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// Título dinâmico que atualiza quando o produto carrega
useHead({
  title: computed(() => product.value
    ? `${product.value.name} - MegaShop`
    : 'Loading... - MegaShop'
  )
})
</script>

Saída:

TEXT
// Execução Bem-sucedida

(3) ▶Exemplo: Configuração Padrão Global

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      title: 'MegaShop - Premium E-Commerce',
      titleTemplate: '%s | MegaShop',
      meta: [
        { name: 'description', content: 'Over 1 million products shipped worldwide' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1' },
        { charset: 'utf-8' }
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
      ]
    }
  }
})

Saída:

TEXT
// Execução Bem-sucedida

4. SEO Estruturado com useSeoMeta

(1) Comparação entre useSeoMeta e useHead

Dimensão useHead useSeoMeta
Foco Gerenciamento Geral do Head Atalhos Específicos para SEO
Estilo de API Array de Objetos Pares Chave-Valor
OG/Twitter Requer entrada manual de meta tags Feito em uma linha
Segurança de Tipo ⚠️ Verificar documentação ✅ Dicas de tipo completas
Desduplicação ⚠️ Gerenciamento Manual ✅ Desduplicação Automática

(1) ▶Exemplo: SEO da Página de Detalhes do Produto

VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// Metadados SEO estruturados - type-safe
useSeoMeta({
  title: () => `${product.value?.name} - Buy Online`,
  ogTitle: () => `${product.value?.name} - MegaShop`,
  description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. ${product.value?.reviewCount} reviews, ${product.value?.rating} stars. Free shipping worldwide.`,
  ogDescription: () => `Premium ${product.value?.name} - $${product.value?.price} USD`,
  ogImage: () => product.value?.image || '/images/og-default.jpg',
  ogUrl: () => `https://megashop.com/products/${route.params.id}`,
  ogType: 'product',
  twitterCard: 'summary_large_image',
  twitterTitle: () => `${product.value?.name} - MegaShop`,
  twitterImage: () => product.value?.image || '/images/og-default.jpg'
})
</script>

Saída:

TEXT
// Execução Bem-sucedida

(2) ▶Exemplo: SEO da Página Inicial

TYPESCRIPT
// pages/index.vue
useSeoMeta({
  title: 'MegaShop - Over 1 Million Products',
  ogTitle: 'MegaShop - Premium E-Commerce Platform',
  description: 'Shop over 1 million products with free worldwide shipping. Electronics, fashion, home & garden at the best prices.',
  ogDescription: 'Discover 1 million+ products on MegaShop. Free shipping on orders over $50 USD.',
  ogImage: '/images/og-homepage.jpg',
  ogUrl: 'https://megashop.com',
  ogType: 'website'
})

Saída:

TEXT
// Execução Bem-sucedida

5. Dados Estruturados JSON-LD

(1) Impacto dos Dados Estruturados nos Resultados de Busca

Tipo de Dados Resultados Rich Snippet do Google Compatível com MegaShop
Product Preço/Avaliação/Estoque ✅ Página de Detalhes do Produto
BreadcrumbList Navegação por Breadcrumbs ✅ Todas as Páginas
Organization Informações da Empresa ✅ Página Inicial
Website Caixa de Busca do Site ✅ Página Inicial
Review Resumo de Avaliações ✅ Página do Produto

(1) ▶Exemplo: JSON-LD de Produto

VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// Dados estruturados JSON-LD para resultados rich do Google
useHead({
  script: [
    {
      type: 'application/ld+json',
      innerHTML: computed(() => JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Product',
        name: product.value?.name,
        image: product.value?.image,
        description: product.value?.description,
        sku: `MEGA-${product.value?.id}`,
        offers: {
          '@type': 'Offer',
          url: `https://megashop.com/products/${route.params.id}`,
          priceCurrency: 'USD',
          price: product.value?.price,
          availability: product.value?.inStock
            ? 'https://schema.org/InStock'
            : 'https://schema.org/OutOfStock'
        },
        aggregateRating: {
          '@type': 'AggregateRating',
          ratingValue: product.value?.rating,
          reviewCount: product.value?.reviewCount
        }
      }))
    }
  ]
})
</script>

Saída:

TEXT
// Execução Bem-sucedida

(2) ▶Exemplo: JSON-LD de Breadcrumb

TYPESCRIPT
// composables/useBreadcrumbLd.ts
export function useBreadcrumbLd(items: { name: string; url: string }[]) {
  useHead({
    script: [{
      type: 'application/ld+json',
      innerHTML: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'BreadcrumbList',
        itemListElement: items.map((item, index) => ({
          '@type': 'ListItem',
          position: index + 1,
          name: item.name,
          item: item.url
        }))
      })
    }]
  })
}

// Uso na página
useBreadcrumbLd([
  { name: 'Home', url: 'https://megashop.com' },
  { name: 'Products', url: 'https://megashop.com/products' },
  { name: 'Premium Headphones', url: 'https://megashop.com/products/123' }
])

Saída:

TEXT
// Execução Bem-sucedida

6. Sitemap e robots.txt

(1) ▶Exemplo: Instalando @nuxtjs/sitemap

BASH
npm install @nuxtjs/sitemap

Saída:

TEXT
# Comando executado com sucesso
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/sitemap'],

  sitemap: {
    hostname: 'https://megashop.com',
    gzip: true,
    routes: async () => {
      // Rotas dinâmicas para 1 milhão de produtos
      const products = await $fetch('/api/products/all-ids')
      return products.map((id: number) => ({
        loc: `/products/${id}`,
        lastmod: new Date().toISOString(),
        changefreq: 'daily',
        priority: 0.8
      }))
    },
    defaults: {
      changefreq: 'weekly',
      priority: 0.5
    }
  }
})

(2) ▶Exemplo: robots.txt

TEXT
// public/robots.txt
User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Disallow: /profile/

Sitemap: https://megashop.com/sitemap.xml

Saída:

TEXT
Execução Bem-sucedida

(1) Comparação de Estratégias de Sitemap

Estratégia Vantagens Desvantagens Aplicabilidade
Sitemap de arquivo único sitemap.xml Simples ≤ 50.000 URLs Site pequeno
Sitemap Index Suporta milhões de URLs Requer divisão MegaShop
Gerar Rotas Dinamicamente Sobrescrever Novas Páginas Automaticamente Consultas em Tempo de Build Páginas de Produtos
Geração automática pelo módulo Zero configuração Limitado Sites de pequeno a médio porte

7. Exemplo Completo: Guia SEO Completo para Páginas de Produtos do MegaShop

VUE
<!-- pages/products/[id].vue -->
<template>
  <div v-if="product" class="product-page">
    <h1>{{ product.name }}</h1>
    <p class="price">${{ product.price }} USD</p>
    <p>{{ product.reviewCount }} reviews · {{ product.rating }} stars</p>
  </div>
</template>

<script setup lang="ts">
const route = useRoute()
const config = useRuntimeConfig()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
const productUrl = `${config.public.siteUrl}/products/${route.params.id}`)

// SEO Meta
useSeoMeta({
  title: () => `${product.value?.name} - MegaShop`,
  ogTitle: () => product.value?.name,
  description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. Free shipping. ${product.value?.reviewCount} reviews.`,
  ogDescription: () => `${product.value?.name} - $${product.value?.price} USD on MegaShop`,
  ogImage: () => product.value?.image,
  ogUrl: () => productUrl,
  ogType: 'product',
  twitterCard: 'summary_large_image'
})

// URL Canônica
useHead({
  link: [{ rel: 'canonical', href: productUrl }]
})

// JSON-LD
useHead({
  script: [{
    type: 'application/ld+json',
    innerHTML: computed(() => JSON.stringify({
      '@context': 'https://schema.org',
      '@type': 'Product',
      name: product.value?.name,
      image: product.value?.image,
      offers: {
        '@type': 'Offer',
        priceCurrency: 'USD',
        price: product.value?.price,
        availability: product.value?.inStock ? 'InStock' : 'OutOfStock'
      },
      aggregateRating: {
        '@type': 'AggregateRating',
        ratingValue: product.value?.rating,
        reviewCount: product.value?.reviewCount
      }
    }))
  }]
})
</script>

❓Perguntas Frequentes

P useSeoMeta e useHead podem ser usados juntos?
R Sim, eles operam na mesma instância Head. useSeoMeta gerencia tags SEO, enquanto useHead gerencia outras tags (canonical/JSON-LD/style).
P Como lidar com um sitemap para uma página de produto com um milhão de itens?
R Use Sitemap Index para dividir em múltiplos sub-sitemaps (cada um com ≤ 50 mil URLs). O módulo @nuxtjs/sitemap suporta divisão automática.
P O innerHTML do JSON-LD representa um risco de XSS?
R O Nuxt 3 aplica medidas de segurança ao innerHTML de tags script. No entanto, é recomendável usar JSON.stringify e escapar dados dinâmicos para prevenir injeção.
P Os metadados SEO funcionam no modo CSR?
R Crawlers de mecanismos de busca não suportam meta tags renderizadas via CSR. Páginas que requerem SEO devem usar SSR, ISR ou SSG. Meta tags em páginas CSR só aparecem após a hidratação do lado do cliente.
P Como usar titleTemplate?
R Configure titleTemplate: '%s | MegaShop' no nuxt.config.ts. Na página, use useHead para definir apenas o conteúdo do título, e o template será construído automaticamente.
P Existem requisitos de tamanho para imagens ogImage?
R O Facebook recomenda 1200x630px, e o Twitter recomenda 1200x600px (summary_large_image). Imagens muito pequenas podem não ser exibidas.

📖Resumo


📝Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Use useHead para definir o título e a meta description da página inicial, então veja o código fonte para verificar.
  2. Exercício Avançado (Dificuldade: ⭐⭐): Use useSeoMeta para configurar metadados completos de OG e Twitter Card para a página de detalhes do produto, e valide usando o Facebook Sharing Debugger.
  3. Desafio (Dificuldade: ⭐⭐⭐): Implemente geração automática de JSON-LD para páginas de produtos, JSON-LD para breadcrumbs e sitemaps, e valide os dados estruturados usando o Google Rich Results Test.

---|

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%