404 Not Found

404 Not Found


nginx

Otimização de Desempenho

O MegaShop está no ar, mas sua pontuação no Lighthouse é apenas 45 — leva 4,5 segundos para carregar a primeira tela, as imagens não estão otimizadas, e o bundle JS é muito grande. Charlie precisa de uma pontuação Lighthouse de 90+ e um LCP de menos de 2 segundos na primeira tela para se manter competitivo.

1. O Que Você Vai Aprender


2. Uma História Real de um Arquiteto

(1) Ponto Crítico: Pontuação Lighthouse de 45, 4,5 segundos para a primeira pintura de conteúdo

Alice abriu o MegaShop no celular e levou 4,5 segundos para os produtos aparecerem. Charlie executou uma auditoria Lighthouse e descobriu que o bundle JS tinha 2,8 MB, todas as imagens eram PNGs não comprimidos, não havia cabeçalhos de cache, e o código de 50 componentes carregava na primeira tela.

(2) Solução com Otimização de Desempenho do Nuxt 3

O Nuxt 3 inclui uma variedade de recursos de otimização de desempenho embutidos:

TYPESCRIPT
// Otimização de imagens com @nuxt/image
<NuxtImg src="/products/123.webp" width="400" height="400" loading="lazy" />

(3) Desempenho: Pontuação Lighthouse de 92, LCP de 1,3 segundos

Após a otimização, o tamanho do bundle JS foi reduzido para 180 KB (gzip), imagens são automaticamente servidas como WebP e são responsivas, o LCP da primeira tela é de 1,3 segundos, e a pontuação Lighthouse é 92.


3. Code Splitting e Tree Shaking

(1) Árvore de Decisão de Otimização de Desempenho

100%
flowchart TB
    A[Performance Issue] --> B{What type?}
    B -->|Slow first paint| C[Code Splitting]
    B -->|Large images| D[Image Optimization]
    B -->|Slow subsequent loads| E[Caching Strategy]
    B -->|JS too large| F[Tree Shaking]

    C --> C1[Lazy components]
    C --> C2[Dynamic imports]
    D --> D1[@nuxt/image module]
    D --> D2[WebP conversion]
    E --> E1[HTTP Cache Headers]
    E --> E2[Nitro KV Cache]
    F --> F1[Check bundle with rollup-plugin-visualizer]

(2) Análise de Bundle

BASH
npm install -D rollup-plugin-visualizer
TYPESCRIPT
// nuxt.config.ts
import { visualizer } from 'rollup-plugin-visualizer'

export default defineNuxtConfig({
  vite: {
    plugins: [
      visualizer({ filename: 'bundle-stats.html', open: true })
    ],
    build: {
      rollupOptions: {
        output: {
          manualChunks: {
            'vendor': ['vue', 'vue-router'],
            'pinia': ['pinia']
          }
        }
      }
    }
  }
})

(1) ▶Exemplo: Code Splitting com Lazy Component

VUE
<template>
  <div>
    <!-- Essencial: carregado imediatamente -->
    <AppHeader />
    <ProductHero :product="featured" />

    <!-- Abaixo da dobra: lazy loading -->
    <LazyProductGrid :products="all" />
    <LazyProductReviews :product-id="id" />

    <!-- Condicional: carregado apenas quando visível -->
    <LazyNewsletterSignup v-if="showNewsletter" />
  </div>
</template>

Saída:

TEXT
// Execução Bem-sucedida

(3) Comparação Antes e Depois da Otimização

Métrica Antes da Otimização Após a Otimização Melhoria
Bundle JS (gzip) 2,8 MB 180 KB -94%
Número de componentes na primeira tela 50 8 -84%
Download JS na Primeira Tela 2,8 MB 85 KB -97%
LCP 4,5s 1,3s -71%

4. Otimização de Imagens

(1) ▶Exemplo: Instalando @nuxt/image

BASH
npm install @nuxt/image

Saída:

TEXT
# Comando executado com sucesso
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  image: {
    quality: 80,
    format: ['webp', 'avif'],
    screens: {
      xs: 320, sm: 640, md: 768, lg: 1024, xl: 1280, xxl: 1536
    }
  }
})

(2) ▶Exemplo: NuxtImg Imagens Responsivas

VUE
<template>
  <div>
    <!-- Auto WebP/AVIF + srcset responsivo -->
    <NuxtImg
      src="/images/product-123.jpg"
      width="800"
      height="600"
      format="webp"
      loading="lazy"
      sizes="sm:100vw md:50vw lg:33vw"
      :modifiers="{ quality: 80 }"
      alt="Premium Headphones"
    />

    <!-- Placeholder com blur-up -->
    <NuxtImg
      src="/images/hero.jpg"
      placeholder
      width="1920"
      height="1080"
      format="webp"
      alt="MegaShop Hero"
    />
  </div>
</template>

Saída:

TEXT
// Execução Bem-sucedida

(3) ▶Exemplo: NuxtPicture Multi-Formato

VUE
<template>
  <!-- NuxtPicture: auto-seleciona melhor formato por navegador -->
  <NuxtPicture
    src="/images/banner.jpg"
    width="1200"
    height="400"
    format="avif,webp"
    loading="lazy"
    alt="Sale Banner"
  />
</template>

Saída:

TEXT
// Execução Bem-sucedida

(1) Comparação de Formatos de Imagem

Formato Taxa de Compressão Suporte de Navegadores Casos de Uso
AVIF 🟢 Melhor (50% vs. JPG) Chrome/Edge/Firefox Navegadores modernos
WebP 🟢 Alta (30% vs. JPG) Todos os principais navegadores Formato preferido de uso geral
JPEG 🟡 Referência Todos Fallback de compatibilidade
PNG 🔴 Grande Todos Imagens Transparentes

5. Estratégia de Caching

(1) ▶Exemplo: Cabeçalhos de Cache HTTP

TYPESCRIPT
// nuxt.config.ts - Cabeçalhos de cache por rota
export default defineNuxtConfig({
  routeRules: {
    // Assets estáticos: cache imutável de 1 ano
    '/_nuxt/**': {
      headers: { 'cache-control': 'public, max-age=31536000, immutable' }
    },
    // Imagens: cache de 1 dia
    '/images/**': {
      headers: { 'cache-control': 'public, max-age=86400, stale-while-revalidate=604800' }
    },
    // Páginas de produtos: cache ISR
    '/products/**': {
      swr: 86400,
      headers: { 'cache-control': 'public, s-maxage=86400, stale-while-revalidate=3600' }
    }
  }
})

Saída:

TEXT
// Execução Bem-sucedida

(2) ▶Exemplo: API de Cache Nitro KV

TYPESCRIPT
// server/api/products/[id].get.ts - Handler com cache
export default cachedEventHandler(
  async (event) => {
    const id = getRouterParam(event, 'id')
    const product = await fetchProductFromDB(Number(id))
    return product
  },
  {
    maxAge: 60 * 60,        // Cache por 1 hora
    swr: true,               // Servir obsoleto enquanto revalida
    getKey: (event) => `product:${getRouterParam(event, 'id')}`,
    varies: ['Accept-Language'] // Cache diferente por idioma
  }
)

Saída:

TEXT
// Execução Bem-sucedida

(1) Comparação de Hierarquias de Cache

Nível Localização Velocidade Método de Controle
Cache do Navegador Dispositivo do Usuário ⚡⚡⚡ Mais rápido Cabeçalho Cache-Control
Cache de Borda CDN Nó Mais Próximo ⚡⚡ Rápido Configuração CDN + Vary
Cache Nitro KV Memória do Servidor ⚡ Rápido cachedEventHandler
Cache de Página ISR Nitro Storage ⚡ Rápido routeRules swr

6. Exemplo Completo: Configuração de Otimização de Desempenho do MegaShop

TYPESCRIPT
// nuxt.config.ts - Otimização de desempenho completa
export default defineNuxtConfig({
  ssr: true,

  modules: ['@nuxt/image', '@nuxtjs/tailwindcss'],

  // Otimização de imagens
  image: {
    quality: 80,
    format: ['webp', 'avif'],
    screens: { xs: 320, sm: 640, md: 768, lg: 1024, xl: 1280 }
  },

  // Otimização de build Vite
  vite: {
    build: {
      cssCodeSplit: true,
      rollupOptions: {
        output: {
          manualChunks(id) {
            if (id.includes('node_modules')) {
              if (id.includes('pinia')) return 'vendor-pinia'
              if (id.includes('vue')) return 'vendor-vue'
              return 'vendor-libs'
            }
          }
        }
      }
    }
  },

  // Estratégia de cache em nível de rota
  routeRules: {
    '/': { prerender: true },
    '/products': { swr: 3600 },
    '/products/**': { swr: 86400 },
    '/admin/**': { ssr: false },
    '/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } },
    '/images/**': { headers: { 'cache-control': 'public, max-age=86400' } }
  },

  // Dicas de desempenho do app
  experimental: {
    payloadExtraction: true // Reduzir tamanho do payload
  }
})
VUE
<!-- pages/index.vue - Página inicial otimizada -->
<template>
  <div>
    <AppHeader />

    <!-- Acima da dobra: carregamento imediato -->
    <section class="hero">
      <NuxtImg src="/images/hero.jpg" width="1200" height="400" format="webp"
        priority alt="MegaShop" />
      <h1>MegaShop</h1>
    </section>

    <!-- Abaixo da dobra: lazy loading -->
    <LazyProductGrid :products="featured" />

    <!-- Condicional: carregar apenas quando visível -->
    <LazyNewsletterSignup v-if="showNewsletter" />
  </div>
</template>

<script setup lang="ts">
const { data: featured } = await useFetch('/api/products/featured')
const showNewsletter = ref(false)
</script>

❓Perguntas Frequentes

P O que devo fazer se minha pontuação Lighthouse estiver baixa?
R Resolva os problemas por prioridade: 1) Otimização de imagens (WebP/compressão/lazy loading) → 2) Análise do bundle JS (lazy components/Tree Shaking) → 3) Estratégia de caching (cabeçalhos HTTP/ISR) → 4) Otimização de fontes.
P O @nuxt/image suporta URLs de imagens externas?
R Sim. Configure image.domains para adicionar domínios externos: image: { domains: ['cdn.example.com'] }. NuxtImg otimizará automaticamente imagens externas.
P Qual é a diferença entre NuxtImg e uma tag img comum?
R NuxtImg gera automaticamente srcset, converte imagens para WebP/AVIF, corta para se ajustar às dimensões do dispositivo, e habilita lazy loading. Com uma tag img comum, você precisa lidar com todas essas otimizações manualmente.
P Qual tem precedência: cache ISR ou cache HTTP?
R ISR é cache do lado do servidor (armazenado no Nitro), enquanto cache HTTP ocorre na camada do navegador/CDN. Fluxo da requisição: Cache do navegador → Cache CDN → ISR Nitro → renderização dinâmica. Cada camada opera independentemente.
P Quais armadilhas devo observar ao configurar manualChunks?
R Não inclua código do lado do servidor nos chunks do cliente. O Nuxt 3 lida automaticamente com a separação de código do servidor e cliente. manualChunks deve ser usado apenas para dividir bibliotecas de terceiros.
P É difícil alcançar uma pontuação Lighthouse de 90+?
R Você pode chegar a 90+ com SSR, otimização de imagens e uma estratégia de caching. A parte mais difícil é manter o LCP abaixo de 2,5 segundos — você deve simplificar o caminho de renderização crítico e carregar apenas recursos essenciais na primeira tela.

📖Resumo


📝Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Instale @nuxt/image, substitua todas as tags img por NuxtImg, e verifique a conversão automática para WebP.
  2. Exercício Avançado (Dificuldade: ⭐⭐): Use rollup-plugin-visualizer para analisar o bundle, identifique a maior dependência, e configure manualChunks para dividi-la.
  3. Desafio (Dificuldade: ⭐⭐⭐): Alcançe uma pontuação Lighthouse de 90+: Otimização de imagens + code splitting + estratégias de caching, usando Lighthouse CI para auditorias automatizadas

---|

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%