Guia completo de otimização de imagens no Astro: 5 técnicas práticas para acelerar seu site em 50%

No mês passado, montei um blog de tecnologia com Astro. Publiquei todo animado, mas, ao abrir o site, descobri que a primeira dobra levava 6 segundos para carregar. As imagens tinham facilmente 2 ou 3 MB e, no celular, o conteúdo demorava uma eternidade para aparecer. Fiquei sem reação: o desempenho estava péssimo.
Depois, passei dois dias estudando otimização de imagens no Astro. Configurei o componente Image, escolhi formatos, implementei carregamento adiado e integrei uma CDN. Ao final, o carregamento inicial caiu para 1,8 segundo e a nota de desempenho do Lighthouse saltou de 62 para 95. Para ser sincero, fiquei muito feliz quando vi aquele 95.
Neste artigo, compartilho os problemas que encontrei nesses dois dias e tudo o que aprendi, incluindo:
- Um exemplo completo de código para configurar o componente Image do Astro do zero
- Como escolher entre JPEG, PNG, WebP e AVIF
- Melhores práticas de carregamento adiado
- Etapas detalhadas para integrar a CDN da Cloudflare
- Como diagnosticar os problemas mais comuns
Ao terminar a leitura, você também poderá acelerar seu site Astro em mais de 50%. Vamos direto ao ponto.
Por que a otimização de imagens no Astro é tão importante
Muita gente acha que otimizar imagens não é tão importante — afinal, seriam apenas alguns segundos a mais. Mas as imagens costumam representar de 60% a 70% do tamanho total de uma página e são a principal causa de lentidão nos sites.
No meu antigo blog, uma única imagem de capa sem compressão tinha 2,5 MB. Bastavam mais algumas capturas de tela no artigo para a página chegar facilmente a 5 ou 6 MB. Ao abrir o site, o usuário precisava esperar vários segundos só pelas imagens, e a taxa de rejeição ficava assustadoramente alta.
O Google tem requisitos rigorosos para o carregamento de imagens
Entre as Core Web Vitals do Google está o LCP (Largest Contentful Paint), que, em termos simples, mede quanto tempo o conteúdo principal da página leva para aparecer. O Google exige um LCP abaixo de 2,5 segundos; acima de 4 segundos é considerado ruim.
Na maioria dos sites, o elemento de LCP costuma ser justamente a grande imagem de capa ou a imagem da primeira dobra. Se ela demora a carregar, o LCP aumenta e o posicionamento em SEO pode ser afetado.
Resultados reais da otimização
Organizei os dados do meu blog antes e depois da otimização:
Antes:
- Carregamento inicial: 6,2 segundos
- Nota de desempenho do Lighthouse: 62
- Tamanho total das imagens: cerca de 8 MB
- LCP: 4,8 segundos
Depois:
- Carregamento inicial: 1,8 segundo (melhora de 70%)
- Nota de desempenho do Lighthouse: 95 (melhora de 53%)
- Tamanho total das imagens: cerca de 1,2 MB (redução de 85%)
- LCP: 1,3 segundo (melhora de 73%)
Para ser sincero, o resultado superou minhas expectativas. Mais importante: depois da otimização, a taxa de rejeição caiu cerca de 35%, e os usuários ficaram claramente mais dispostos a continuar lendo.
O Astro já é um framework voltado para desempenho. Seria uma pena deixar imagens mal otimizadas comprometerem essa vantagem. A seguir, vamos fazer a otimização passo a passo.
Guia completo do componente Image do Astro
O Astro inclui os componentes <Image /> e <Picture />, criados especificamente para otimizar imagens. Confesso que, no início, a documentação oficial me deixou confuso: para que serviam parâmetros como widths, quality e inferSize? Só entendi depois de testar tudo por conta própria.
Uso básico: Image vs. Picture
Primeiro, o componente <Image />, que é o mais usado:
---
import { Image } from 'astro:assets';
import coverImage from '../assets/blog-cover.jpg';
---
<Image
src={coverImage}
alt="Imagem de capa do blog"
width={1200}
height={630}
/>
Esse componente cuida automaticamente de:
- Comprimir a imagem
- Convertê-la para WebP (comportamento padrão)
- Gerar imagens responsivas
- Otimizar o desempenho de carregamento
Já o componente <Picture /> é mais avançado e permite oferecer vários formatos como fallback:
---
import { Picture } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<Picture
src={heroImage}
formats={['avif', 'webp', 'jpeg']}
alt="Imagem hero"
width={1920}
height={1080}
/>
O navegador tenta carregar AVIF primeiro, por ser o menor. Se não houver suporte, usa WebP; se necessário, recorre a JPEG. Assim, você mantém desempenho e compatibilidade.
Propriedades essenciais em detalhes
No começo, eu também não sabia bem como definir esses parâmetros. Depois de alguns testes, encontrei uma configuração prática:
widths — larguras responsivas
<Image
src={image}
widths={[400, 800, 1200]}
sizes="(max-width: 768px) 400px, (max-width: 1024px) 800px, 1200px"
alt="Imagem responsiva"
/>
Com essa configuração, o Astro gera três tamanhos da imagem, e o navegador escolhe automaticamente o mais adequado para a tela. O celular carrega uma imagem menor, enquanto o desktop carrega uma maior, economizando dados e tempo.
quality — controle de qualidade
<Image
src={image}
quality="mid" // Ou use um número: quality={80}
alt="Imagem do artigo"
/>
low: indicado para miniaturas e imagens de fundomid: suficiente para a maioria dos casos (recomendado)high: indicado quando a qualidade visual é prioridade- Número (0–100): oferece controle preciso
Normalmente uso mid ou 80. A diferença é imperceptível a olho nu, mas o arquivo pode ficar de 30% a 40% menor.
inferSize — a solução para imagens remotas
<Image
src="https://example.com/image.jpg"
inferSize={true}
alt="Imagem remota"
/>
Se você usa uma imagem remota e não conhece suas dimensões, basta adicionar inferSize; o Astro obtém essas informações automaticamente. Esse recurso já me salvou várias vezes.
loading — configuração do carregamento adiado
<!-- Imagem da primeira dobra: carregamento imediato -->
<Image src={hero} loading="eager" alt="Imagem da primeira dobra" />
<!-- Abaixo da primeira dobra: carregamento adiado -->
<Image src={content} loading="lazy" alt="Imagem do conteúdo" />
format — formato de saída
<Image
src={image}
format="webp" // webp | avif | jpeg | png
alt="Formato definido"
/>
Imagens locais vs. remotas
Essa diferença também me confundiu por algum tempo, mas é bem simples:
Imagens locais (recomendado)
---
// Coloque a imagem em src/assets/ ou src/images/
import myImage from '../assets/photo.jpg';
---
<Image src={myImage} alt="Imagem local" />
O Astro otimiza, comprime e empacota automaticamente as imagens locais. Recomendo muito essa abordagem.
Imagens remotas
---
// É necessário autorizar o domínio em astro.config.mjs
---
<Image
src="https://images.unsplash.com/photo-xxx"
width={800}
height={600}
alt="Imagem remota"
/>
Não se esqueça de configurar o domínio em astro.config.mjs:
export default defineConfig({
image: {
domains: ['images.unsplash.com', 'cdn.example.com']
}
});
Imagens do diretório public
<!-- public/logo.png → /logo.png -->
<img src="/logo.png" alt="Logo" />
Importante: imagens no diretório public/ não são otimizadas. Use-o apenas para arquivos pequenos, como o logo e o favicon.
Exemplo prático de código
Esta é a configuração que realmente uso no meu blog:
Imagem de capa do artigo (primeira dobra, pré-carregada)
---
import { Image } from 'astro:assets';
import coverImage from '../assets/blog-cover.jpg';
---
<Image
src={coverImage}
alt="Guia completo de otimização de imagens no Astro"
width={1200}
height={630}
format="webp"
quality={85}
loading="eager"
class="blog-cover"
/>
Imagens dentro do artigo (carregamento adiado)
<Image
src={screenshot}
alt="Captura de tela do exemplo de configuração"
width={800}
height={450}
format="webp"
quality="mid"
loading="lazy"
/>
Avatar do autor (ícone pequeno, pré-carregado)
<Image
src={avatar}
alt="Avatar do autor"
width={48}
height={48}
format="webp"
loading="eager"
/>
Agora que vimos a configuração do componente Image, vamos escolher o formato certo — outra decisão que costuma gerar dúvidas.
Guia completo de formatos de imagem
Com tantas opções, qual formato escolher? JPEG, PNG, WebP, AVIF… Confesso que, no começo, também fiquei perdido. Só entendi o melhor uso de cada formato depois de fazer meus próprios testes.
Comparação dos quatro formatos principais
Esta tabela resume as diferenças:
| Formato | Tipo de compressão | Tamanho do arquivo | Suporte dos navegadores | Uso indicado |
|---|---|---|---|---|
| JPEG | Com perdas | Médio | 100% | Fotos e imagens complexas |
| PNG | Sem perdas | Grande | 100% | Imagens que exigem transparência |
| WebP | Com ou sem perdas | Pequeno | 97%+ | Uso geral (recomendado) |
| AVIF | Com ou sem perdas | Menor | 90%+ | Máxima compressão |
JPEG — formato tradicional com a melhor compatibilidade
- Vantagens: todos os navegadores oferecem suporte e a taxa de compressão é razoável
- Desvantagens: não oferece transparência e comprime menos que WebP
- Indicado para: imagens de artigos, produtos e pessoas
PNG — compressão sem perdas e suporte a transparência
- Vantagens: preserva a qualidade e oferece transparência
- Desvantagens: arquivos grandes, normalmente duas ou três vezes maiores que JPEG
- Indicado para: logos, ícones e imagens com fundo transparente
WebP — promovido pelo Google e com o melhor equilíbrio
- Vantagens: comprime cerca de 30% mais que JPEG, oferece transparência e tem boa compatibilidade
- Desvantagens: alguns pouquíssimos navegadores antigos não oferecem suporte (mas já estamos em 2025…)
- Indicado para: a maioria dos casos; é a minha primeira escolha
AVIF — o formato mais recente e com a maior compressão
- Vantagens: comprime de 20% a 30% mais que WebP e preserva melhor a qualidade
- Desvantagens: compatibilidade um pouco menor e codificação lenta
- Indicado para: cenários em que o desempenho é prioridade máxima
Árvore de decisão para escolher o formato
Não quer analisar tantos parâmetros? Siga este fluxo:
Precisa de transparência?
├─ Sim → WebP (primeira escolha) ou PNG (fallback)
└─ Não → Continue
É uma foto ou imagem complexa?
├─ Sim → WebP (primeira escolha) ou AVIF (máxima compressão)
└─ Não → Continue
É um logo ou ícone?
├─ Sim → SVG (vetorial)
└─ Não → Continue
É uma animação?
└─ WebP (no lugar de GIF)
Minha experiência: WebP atende diretamente a 90% dos casos. Tem boa compatibilidade, comprime bem e dá pouco trabalho.
Como lidar com a compatibilidade entre formatos
Se você quer usar AVIF, mas se preocupa com compatibilidade, ofereça fallbacks com o componente <Picture>:
---
import { Picture } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<Picture
src={heroImage}
formats={['avif', 'webp', 'jpeg']}
alt="Imagem hero"
width={1920}
height={1080}
/>
O navegador segue esta lógica:
- Primeiro tenta AVIF (menor e mais recente)
- Se não houver suporte, usa WebP (segundo menor e bem compatível)
- Como último recurso, usa JPEG (maior e com 100% de compatibilidade)
Assim, os navegadores modernos recebem a melhor experiência sem deixar os antigos sem imagem.
Teste prático de compressão
Fiz um teste com uma imagem original de 2,5 MB:
| Formato | Tamanho do arquivo | Compressão | Qualidade visual |
|---|---|---|---|
| Original (PNG) | 2,5 MB | — | Original |
| JPEG (quality=85) | 450 KB | 82% | Quase nenhuma diferença a olho nu |
| WebP (quality=85) | 180 KB | 93% | Quase nenhuma diferença a olho nu |
| AVIF (quality=85) | 120 KB | 95% | Quase nenhuma diferença a olho nu |
Observe: com a mesma qualidade visual, WebP ficou 60% menor que JPEG, enquanto AVIF ficou 73% menor. O resultado da compressão é realmente impressionante.
Minha recomendação:
- Uso cotidiano: WebP, com boa compatibilidade e compressão
- Máximo desempenho: AVIF + WebP + JPEG, com três níveis de fallback
- Transparência: WebP como prioridade ou PNG como fallback
- Logos e ícones: sempre que possível, use SVG para redimensionamento realmente sem perdas
Depois de escolher os formatos, é hora de configurar o carregamento adiado, que pode reduzir muito o tempo de carregamento inicial.
Melhores práticas de carregamento adiado
Carregamento adiado (lazy loading) significa, em resumo, carregar uma imagem apenas quando ela for necessária. Imagens fora da área visível não são baixadas de imediato; o carregamento começa quando o usuário rola a página e se aproxima delas. Isso reduz bastante o tempo de carregamento inicial.
Como funciona o carregamento adiado
Hoje, os navegadores oferecem suporte nativo ao recurso por meio de um único atributo, loading:
<img src="image.jpg" loading="lazy" alt="Imagem com carregamento adiado" />
O componente Image do Astro já usa carregamento adiado por padrão, sem exigir configuração adicional. Para controlar o comportamento com precisão, faça assim:
<!-- Carregamento adiado (padrão) -->
<Image src={image} loading="lazy" alt="Carregamento adiado" />
<!-- Carregamento imediato -->
<Image src={image} loading="eager" alt="Carregamento imediato" />
O navegador usa a API Intersection Observer para detectar se a imagem está entrando na área visível e inicia o download quando ela se aproxima.
Estratégia para configurar o carregamento adiado
A questão principal é: quais imagens devem ser adiadas e quais devem carregar imediatamente?
Carregamento imediato (loading="eager"):
- Imagens visíveis na primeira dobra, como a imagem hero e a capa
- Logo e ícones da navegação
- Imagens essenciais ao produto, como a imagem principal e o avatar
- Todo conteúdo acima da dobra
Carregamento adiado (loading="lazy"):
- Imagens abaixo da primeira dobra
- Ilustrações e capturas de tela dentro de artigos
- Miniaturas em páginas de listagem
- Imagens do rodapé
- Imagens decorativas
Minha experiência: basta carregar imediatamente uma ou duas imagens da primeira dobra e adiar todas as outras. Assim, a primeira tela aparece rápido sem baixar imagens demais de uma só vez.
Exemplo prático de configuração
Esta é a configuração real do meu blog:
Página inicial do blog
---
import { Image } from 'astro:assets';
---
<!-- Imagem hero da primeira dobra: carregamento imediato -->
<Image
src={heroCover}
loading="eager"
alt="Capa da página inicial do blog"
width={1920}
height={1080}
/>
<!-- Miniaturas da lista de artigos: carregamento adiado -->
{posts.map(post => (
<Image
src={post.thumbnail}
loading="lazy"
alt={post.title}
width={400}
height={225}
/>
))}
Página do artigo
<!-- Imagem no topo do artigo: carregamento imediato -->
<Image
src={article.cover}
loading="eager"
alt={article.title}
width={1200}
height={630}
/>
<!-- Todas as imagens do artigo: carregamento adiado -->
<Image
src={screenshot1}
loading="lazy"
alt="Captura de tela do exemplo de código"
width={800}
height={450}
/>
<Image
src={screenshot2}
loading="lazy"
alt="Comparação dos resultados"
width={800}
height={450}
/>
Galeria de imagens (caso especial)
<!-- Carregue o primeiro grupo imediatamente -->
{gallery.slice(0, 6).map(img => (
<Image src={img} loading="eager" alt={img.alt} />
))}
<!-- Adie as imagens seguintes -->
{gallery.slice(6).map(img => (
<Image src={img} loading="lazy" alt={img.alt} />
))}
Monitoramento de desempenho
Como saber se a otimização funcionou? Use estas ferramentas:
1. Lighthouse (Chrome DevTools)
Pressione F12 para abrir as ferramentas do desenvolvedor, acesse o painel Lighthouse e clique em “Analyze page load”:
- Nota de Performance: deve ficar acima de 90
- LCP: deve ficar abaixo de 2,5 segundos
- CLS: deve ficar próximo de 0, evitando deslocamentos de layout
Antes da otimização, minha nota de Performance era 62 e o LCP era 4,8 segundos. Depois, a nota chegou a 95 e o LCP caiu para 1,3 segundo.
2. Painel Network do Chrome DevTools
Pressione F12 → Network → marque “Disable cache” → atualize a página:
- Confira no gráfico em cascata se a ordem de carregamento das imagens faz sentido
- Verifique se as imagens da primeira dobra carregam primeiro
- Confirme se as imagens adiadas só são carregadas durante a rolagem
3. WebPageTest
Para avaliar o desempenho em condições reais de uso, utilize o WebPageTest e teste o carregamento em diferentes regiões e dispositivos.
Comparação antes e depois:
| Métrica | Antes | Depois | Melhora |
|---|---|---|---|
| Carregamento inicial | 6,2 segundos | 1,8 segundo | 71% |
| LCP | 4,8 segundos | 1,3 segundo | 73% |
| Tamanho total das imagens na primeira dobra | 8 MB | 1,2 MB | 85% |
| Nota de Performance | 62 | 95 | 53% |
A diferença é muito evidente; a experiência do usuário muda completamente.
Depois de configurar o carregamento adiado, vamos integrar uma CDN para acelerar ainda mais o acesso global.
Integração prática de uma CDN de imagens
No começo, confesso que hesitei em adotar uma CDN porque temia uma configuração complexa e custos altos. Depois descobri que a cota gratuita da Cloudflare era mais que suficiente e que a configuração não era difícil, então decidi integrá-la.
Por que usar uma CDN
Uma CDN (Content Delivery Network) armazena cópias das suas imagens em pontos de presença distribuídos pelo mundo. Quando alguém acessa o site, baixa os arquivos do ponto mais próximo e recebe o conteúdo mais rápido.
Vantagens de uma CDN:
- Aceleração global: um usuário em Pequim carrega de um ponto de presença em Pequim; um usuário em Nova York, de um ponto em Nova York
- Menos carga no servidor: todas as solicitações de imagens passam pela CDN, aliviando bastante o servidor de origem
- Otimização automática: muitas CDNs convertem formatos e comprimem imagens automaticamente
- Redundância: se um ponto de presença falhar, outros continuam disponíveis
Depois que integrei a CDN da Cloudflare ao meu blog, o carregamento para usuários no exterior ficou cerca de 60% mais rápido.
Integração com o Cloudflare Image Resizing
A Cloudflare oferece o serviço Image Resizing, que funciona muito bem com o Astro.
Etapa 1: ative o Cloudflare Image Resizing
Entre no Cloudflare Dashboard → selecione seu domínio → Speed → Optimization → ative “Image Resizing”.
O plano gratuito inclui uma cota de 50 mil transformações por mês, suficiente para um blog pessoal.
Etapa 2: configure astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server', // Ou 'hybrid'
adapter: cloudflare({
imageService: 'cloudflare' // Usa o serviço de imagens da Cloudflare
}),
image: {
// Autorize os domínios caso use imagens remotas
domains: ['images.unsplash.com', 'cdn.example.com']
}
});
Etapa 3: autorize domínios, caso use imagens remotas
Se suas imagens vêm de uma CDN externa, adicione o domínio em image.domains:
export default defineConfig({
image: {
domains: [
'images.unsplash.com',
'cdn.example.com',
'res.cloudinary.com'
]
}
});
Após a configuração, o componente Image do Astro usa automaticamente o serviço de imagens da Cloudflare para fazer a otimização.
Outras opções de CDN
Além da Cloudflare, existem outras alternativas interessantes:
Cloudinary
É uma CDN especializada em imagens e oferece um SDK para Astro muito fácil de usar:
npm install @cloudinary/url-gen
---
import { CldImage } from 'astro-cloudinary';
---
<CldImage
src="sample"
width={800}
height={600}
alt="Imagem da Cloudinary"
/>
A vantagem é o conjunto robusto de recursos, incluindo transformações, filtros e marcas-d’água. A desvantagem é que a cota gratuita é limitada e o uso excedente é cobrado.
Uploadcare
Também é uma CDN especializada em imagens e se destaca pela facilidade de envio e processamento:
// astro.config.mjs
export default defineConfig({
image: {
service: {
entrypoint: 'uploadcare-astro',
config: {
publicKey: 'your-public-key'
}
}
}
});
Cloudflare R2
Se você tem muitas imagens, pode usar o Cloudflare R2 como armazenamento de objetos:
// astro.config.mjs
export default defineConfig({
build: {
assetsPrefix: 'https://your-r2-domain.com'
}
});
A vantagem do R2 é não cobrar pela transferência de saída; você paga apenas pelo armazenamento, o que oferece uma ótima relação custo-benefício.
Cuidados ao configurar a CDN
Já enfrentei todos estes problemas, então vale o alerta:
1. No modo SSR, ative a otimização por domínio
Se você usa SSR (Server-Side Rendering), lembre-se de ativar o Image Resizing no Cloudflare Dashboard para cada domínio.
2. É obrigatório autorizar o domínio das imagens remotas
Sem essa configuração, você verá o erro:
Image's component src parameter is not allowed for this image.
Solução: adicione o domínio em image.domains no arquivo astro.config.mjs.
3. O modo compile otimiza apenas durante o build
adapter: cloudflare({
imageService: 'compile' // Otimiza apenas durante o build
})
Nesse modo, as imagens são otimizadas uma vez durante o empacotamento e não são processadas em runtime. É adequado para sites totalmente estáticos.
4. Acompanhe a cota gratuita
| Serviço de CDN | Cota gratuita | Preço excedente |
|---|---|---|
| Cloudflare Image Resizing | 50 mil transformações/mês | US$ 5/50 mil transformações |
| Cloudinary | 25 créditos/mês | Cobrança por uso |
| Uploadcare | 3 GB de armazenamento + 3 GB de transferência | Cobrança por uso |
| Cloudflare R2 | 10 GB de armazenamento | US$ 0,015/GB/mês |
Para um blog pessoal, as cotas gratuitas costumam ser suficientes. Em projetos comerciais, acompanhe os custos.
Exemplo de comparação de custos:
Meu blog recebe cerca de 20 mil acessos por mês e faz aproximadamente 100 mil solicitações de imagens:
- Cloudflare: gratuito (dentro da cota de 50 mil transformações)
- Cloudinary: exige um plano pago (a partir de US$ 9/mês)
- Uploadcare: exige um plano pago (a partir de US$ 25/mês)
Por isso escolhi a Cloudflare: econômica e fácil de usar.
Depois de configurar a CDN, vamos ver como diagnosticar os problemas mais comuns — já encontrei praticamente todos eles.
Problemas comuns e diagnóstico
Nesta seção, reuni todos os problemas que enfrentei para ajudar você a evitá-los.
A imagem não aparece
Problema: o espaço da imagem fica vazio ou aparece o ícone de imagem quebrada.
Possíveis causas e soluções:
1. Caminho de import incorreto
// ❌ Incorreto: caminho relativo errado
import image from './assets/photo.jpg';
// ✅ Correto: confira o nível do caminho
import image from '../assets/photo.jpg';
2. Domínio da imagem remota não autorizado
// astro.config.mjs
export default defineConfig({
image: {
domains: ['images.unsplash.com'] // Não se esqueça desta configuração
}
});
A mensagem de erro costuma ser:
Image's component src parameter is not allowed for this image.
3. Formato de imagem incompatível
O Astro oferece suporte a JPG, JPEG, PNG, WEBP, AVIF, GIF e SVG.
Formatos como TIFF e BMP precisam ser convertidos primeiro.
Imagem borrada ou com baixa qualidade
Problema: a imagem aparece borrada ou com uma perda evidente de qualidade.
Soluções:
1. Ajuste o parâmetro quality
<!-- Qualidade muito baixa -->
<Image src={img} quality="low" alt="Imagem muito borrada" />
<!-- Qualidade mais alta -->
<Image src={img} quality={85} alt="Imagem bem mais nítida" />
2. A resolução original é insuficiente
Se a imagem original tem apenas 400 × 300 e você insiste em exibi-la com 1200 × 900, ela ficará borrada. A solução é usar uma imagem original com resolução maior.
3. Configuração incorreta das dimensões responsivas
<!-- ❌ Dimensões muito pequenas -->
<Image
src={img}
widths={[200, 400]}
sizes="(max-width: 1920px) 400px"
alt="Ficará borrada no desktop"
/>
<!-- ✅ Forneça tamanhos suficientes -->
<Image
src={img}
widths={[400, 800, 1200, 1920]}
sizes="(max-width: 768px) 400px, (max-width: 1024px) 800px, 1200px"
alt="Nítida em todas as telas"
/>
Erro durante o build
Problema: ao executar npm run build, ocorre um erro relacionado a imagens.
1. Falha ao instalar o Sharp
Mensagem de erro:
Error: Could not load the "sharp" module
Solução:
# Exclua node_modules e reinstale as dependências
rm -rf node_modules package-lock.json
npm install
# Ou reinstale apenas o sharp
npm uninstall sharp
npm install sharp
Se ainda não funcionar, tente instalar uma versão específica:
npm install [email protected]
2. Memória insuficiente
Mensagem de erro:
FATAL ERROR: Reached heap limit Allocation failed
Solução: aumente o limite de memória do Node.js:
# package.json
{
"scripts": {
"build": "NODE_OPTIONS='--max-old-space-size=4096' astro build"
}
}
3. Formato de imagem incompatível
Se a imagem está em HEIC ou TIFF, o Sharp pode não conseguir processá-la. Converta-a antes para JPG ou PNG.
Problemas de imagem no modo SSR
Problema: tudo funciona no desenvolvimento local, mas as imagens não aparecem depois da implantação no Cloudflare Pages ou Workers.
Soluções:
1. Configure o imageService correto
// astro.config.mjs
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare({
imageService: 'cloudflare' // Configuração essencial
})
});
2. Confira o modo output
export default defineConfig({
output: 'server', // Ou 'hybrid'
// output: 'static' não oferece suporte ao imageService da Cloudflare
});
3. Caminho das imagens locais
No modo SSR, as imagens locais precisam ficar no diretório src/, não em public/:
---
// ✅ Correto: src/assets/
import image from '../assets/photo.jpg';
// ❌ Incorreto: public/ não é otimizado
// <img src="/photo.jpg" />
---
<Image src={image} alt="Forma correta" />
Checklist de diagnóstico
Quando algo der errado, verifique nesta ordem:
- ✓ O caminho do import está correto?
- ✓ O formato da imagem é compatível?
- ✓ O domínio da imagem remota está na lista de permissões?
- ✓ O parâmetro de qualidade é adequado?
- ✓ O Sharp foi instalado corretamente?
- ✓ A configuração do modo SSR está correta?
- ✓ Há erros no Console do navegador?
- ✓ Qual é o status das solicitações de imagem no painel Network?
Depois de tantos detalhes, vamos resumir.
Conclusão
Passei dois dias estudando a otimização de imagens no Astro e registrei aqui o que aprendi para ajudar quem está enfrentando os mesmos problemas.
Recapitulando os pontos principais:
- Configuração do componente Image: substitua a tag
<img>pelo componente<Image />para automatizar compressão, conversão de formato e tratamento responsivo - Escolha do formato: WebP atende a 90% dos casos; para desempenho máximo, use AVIF com fallback; para transparência, escolha WebP ou PNG
- Estratégia de carregamento adiado: carregue imediatamente apenas uma ou duas imagens da primeira dobra e adie todas as demais, reduzindo em mais de 50% o volume inicial
- Integração com CDN: adote a CDN da Cloudflare; a cota gratuita é suficiente e o acesso global pode ficar 60% mais rápido
- Diagnóstico: siga o checklist item por item; 90% dos problemas estão no caminho, na configuração ou na instalação do Sharp
Depois da otimização, o carregamento inicial do meu blog caiu de 6,2 para 1,8 segundo, a nota do Lighthouse subiu de 62 para 95 e a taxa de rejeição caiu 35%. O retorno desse trabalho foi excelente.
Recomendo começar agora com estas ações:
- Abra o site, pressione F12 e execute um teste do Lighthouse para conferir a nota atual
- Verifique os formatos e converta para WebP tudo o que for possível
- Adicione
loading="lazy"às imagens fora da primeira dobra - Se houver muitas imagens, considere adotar a CDN da Cloudflare
A otimização de imagens é um processo contínuo; não é preciso fazer tudo de uma vez. Cada melhoria aumenta um pouco o desempenho e torna a experiência do usuário melhor.
Se você encontrar algum problema durante a otimização ou tiver uma experiência melhor para compartilhar, deixe um comentário. Espero que seu site fique cada vez mais rápido!
Guia completo de otimização de imagens no Astro: deixe seu site 50% mais rápido
Cinco técnicas práticas para reduzir o carregamento inicial de 6 para 1,8 segundo e elevar a nota do Lighthouse de 62 para 95
⏱️ Estimated time: 2 hr
- 1
Step 1: Entenda a importância da otimização de imagens e defina as metas
Por que otimizar imagens é importante:
• Elas costumam representar de 60% a 70% do tamanho total de uma página e são a principal causa de lentidão
• No meu antigo blog, uma única imagem de capa sem compressão tinha 2,5 MB
• Bastavam mais algumas capturas de tela no artigo para a página chegar facilmente a 5 ou 6 MB
• Ao abrir o site, o usuário precisava esperar vários segundos só pelas imagens, o que elevava muito a taxa de rejeição
O Google tem requisitos rigorosos para o carregamento de imagens:
• Entre as Core Web Vitals está o LCP (Largest Contentful Paint)
• Em termos simples, ele mede quanto tempo o conteúdo principal da página leva para aparecer
• O Google exige LCP abaixo de 2,5 segundos; acima de 4 segundos é considerado ruim
• Na maioria dos sites, o LCP costuma ser a grande imagem de capa ou a imagem da primeira dobra
• Se a imagem demora a carregar, o LCP aumenta e o posicionamento em SEO pode ser afetado
Metas de otimização:
• Reduzir o carregamento inicial de 6,2 para 1,8 segundo (melhora de 71%)
• Elevar a nota de desempenho do Lighthouse de 62 para 95 (melhora de 53%)
• Reduzir o tamanho total das imagens de cerca de 8 MB para aproximadamente 1,2 MB (redução de 85%)
• Reduzir o LCP de 4,8 para 1,2 segundo (melhora de 75%) - 2
Step 2: Técnica 1: use o componente Image do Astro
Vantagens do componente Image do Astro:
• Otimiza automaticamente formato, dimensões e carregamento adiado
• Substitui a tag <img> pelo componente <Image />
• Automatiza compressão, conversão de formato e tratamento responsivo
Etapas de configuração:
1. Instale a integração @astrojs/image (execute npx astro add image)
2. Configure imageService em astro.config.mjs (escolha sharp ou squoosh)
3. Use o componente Image:
import { Image } from 'astro:assets';
<Image src={image} alt="Descrição" />
Atenção ao caminho das imagens locais:
• No modo SSR, elas precisam ficar no diretório src/, não em public/
• Correto: import image from '../assets/photo.jpg'; <Image src={image} alt="Forma correta" />
• Incorreto: arquivos em public/ não são otimizados - 3
Step 3: Técnicas 2 e 3: escolha o formato adequado e configure o carregamento adiado
Escolha do formato:
• JPEG: indicado para fotos e imagens complexas; oferece a melhor compatibilidade
• PNG: indicado para ícones e fundos transparentes; gera arquivos maiores
• WebP: fica de 30% a 50% menor que JPEG, tem suporte nos navegadores modernos e atende a 90% dos casos
• AVIF: fica de 20% a 30% menor que WebP; é o formato mais recente, mas tem compatibilidade um pouco menor, por isso deve ser usado com fallback quando o objetivo é a máxima compressão
Configuração do carregamento adiado:
• Carregue imediatamente apenas uma ou duas imagens da primeira dobra e adie todas as demais
• Isso pode reduzir em mais de 50% o volume inicial carregado
• Use o atributo loading="lazy" ou a propriedade loading do componente Image - 4
Step 4: Técnicas 4 e 5: acelere com uma CDN e otimize as dimensões
Integração com a CDN da Cloudflare:
• Use Cloudflare Images ou o armazenamento R2
• Configure otimização e conversão automática de formatos
• Aproveite mais de 300 pontos de presença no mundo sem custo
• Nos meus testes, a latência caiu para um terço
Etapas de configuração:
1. Ative Images ou R2 no Cloudflare Dashboard
2. Configure imageService para usar a Cloudflare
3. Envie as imagens para a Cloudflare
4. Carregue as imagens pela URL da Cloudflare
Otimização das dimensões:
• Use os atributos srcset e sizes para carregar o tamanho adequado em cada dispositivo
• Defina width e height no componente Image para garantir dimensões apropriadas - 5
Step 5: Resolva problemas e aplique as melhores práticas
Checklist de diagnóstico:
1. Verifique se o caminho do import está correto
2. Verifique se o formato da imagem é compatível
3. Verifique se o domínio da imagem remota está na lista de permissões
4. Verifique se o parâmetro de qualidade é adequado
5. Verifique se o Sharp foi instalado corretamente
Problemas comuns:
• Falha ao instalar o Sharp → confirme a versão do Node e execute npm install sharp
• Falha ao otimizar uma imagem remota → confira a lista de domínios permitidos
• Modo SSR incompatível → confirme se output está definido como 'server' ou 'hybrid'
Melhores práticas:
• A otimização de imagens é um processo contínuo; não é preciso fazer tudo de uma vez
• Cada melhoria aumenta um pouco o desempenho e torna a experiência do usuário melhor
Comece agora com estas ações:
1. Abra o site, pressione F12 e execute um teste do Lighthouse para conferir a nota atual
2. Verifique os formatos e converta para WebP tudo o que for possível
3. Adicione loading="lazy" às imagens fora da primeira dobra
4. Se houver muitas imagens, considere adotar a CDN da Cloudflare
FAQ
Por que a otimização de imagens é tão importante?
• Elas costumam representar de 60% a 70% do tamanho total de uma página e são a principal causa de lentidão
• No meu antigo blog, uma única imagem de capa sem compressão tinha 2,5 MB; com mais algumas capturas de tela, a página chegava facilmente a 5 ou 6 MB
• Ao abrir o site, o usuário precisava esperar vários segundos só pelas imagens, o que elevava muito a taxa de rejeição
O Google tem requisitos rigorosos para o carregamento de imagens:
• Entre as Core Web Vitals do Google está o LCP (Largest Contentful Paint)
• Em termos simples, ele mede quanto tempo o conteúdo principal da página leva para aparecer
• O Google exige LCP abaixo de 2,5 segundos; acima de 4 segundos é considerado ruim
• Na maioria dos sites, o LCP costuma ser a grande imagem de capa ou a imagem da primeira dobra
• Se a imagem demora a carregar, o LCP aumenta e o posicionamento em SEO pode ser afetado
Quais resultados a otimização de imagens no Astro pode trazer?
• O carregamento inicial caiu de 6,2 para 1,8 segundo (melhora de 71%)
• A nota de desempenho do Lighthouse subiu de 62 para 95 (melhora de 53%)
• O tamanho total das imagens caiu de cerca de 8 MB para aproximadamente 1,2 MB (redução de 85%)
• O LCP caiu de 4,8 para 1,2 segundo (melhora de 75%)
Depois da otimização, o carregamento inicial do meu blog caiu de 6,2 para 1,8 segundo, a nota do Lighthouse subiu de 62 para 95 e a taxa de rejeição caiu 35%. O retorno desse trabalho foi excelente.
Como usar o componente Image do Astro?
• Otimiza automaticamente formato, dimensões e carregamento adiado
• Substitui a tag <img> pelo componente <Image />
• Automatiza compressão, conversão de formato e tratamento responsivo
Etapas de configuração:
1) Instale a integração @astrojs/image (execute npx astro add image)
2) Configure imageService em astro.config.mjs (escolha sharp ou squoosh)
3) Use o componente Image: import { Image } from 'astro:assets'; <Image src={image} alt="Descrição" />
Atenção ao caminho das imagens locais:
• No modo SSR, elas precisam ficar no diretório src/, não em public/
• Correto: import image from '../assets/photo.jpg'; <Image src={image} alt="Forma correta" />
• Incorreto: arquivos em public/ não são otimizados
Como escolher entre JPEG, PNG, WebP e AVIF?
• JPEG (indicado para fotos e imagens complexas; oferece a melhor compatibilidade)
• PNG (indicado para ícones e fundos transparentes; gera arquivos maiores)
• WebP (fica de 30% a 50% menor que JPEG, tem suporte nos navegadores modernos e atende a 90% dos casos)
• AVIF (fica de 20% a 30% menor que WebP; é o formato mais recente, mas tem compatibilidade um pouco menor, por isso deve ser usado com fallback quando o objetivo é a máxima compressão)
Minha recomendação:
• WebP atende a 90% dos casos
• Para a máxima compressão, use AVIF com fallback
• Quando precisar de transparência, use WebP ou PNG
Como configurar o carregamento adiado e a aceleração por CDN?
• Carregue imediatamente apenas uma ou duas imagens da primeira dobra e adie todas as demais
• Isso pode reduzir em mais de 50% o volume inicial carregado
• Use o atributo loading="lazy" ou a propriedade loading do componente Image
Integração com a CDN da Cloudflare:
• Use Cloudflare Images ou o armazenamento R2
• Configure otimização e conversão automática de formatos
• Aproveite mais de 300 pontos de presença no mundo sem custo
• Nos meus testes, a latência caiu para um terço
Etapas de configuração:
1) Ative Images ou R2 no Cloudflare Dashboard
2) Configure imageService para usar a Cloudflare
3) Envie as imagens para a Cloudflare
4) Carregue as imagens pela URL da Cloudflare
Como diagnosticar problemas na otimização de imagens?
1) Verifique se o caminho do import está correto
2) Verifique se o formato da imagem é compatível
3) Verifique se o domínio da imagem remota está na lista de permissões
4) Verifique se o parâmetro de qualidade é adequado
5) Verifique se o Sharp foi instalado corretamente
Problemas comuns:
• Falha ao instalar o Sharp → confirme a versão do Node e execute npm install sharp
• Falha ao otimizar uma imagem remota → confira a lista de domínios permitidos
• Modo SSR incompatível → confirme se output está definido como 'server' ou 'hybrid'
Siga o checklist item por item: 90% dos problemas estão no caminho, na configuração ou na instalação do Sharp.
20 min de leitura · Publicado em: 3 dez 2025 · Atualizado em: 8 set 2026
Guia Astro
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Falha no build do Astro? Diagnostique estas 7 causas comuns em 5 minutos
Seu build do Astro falhou e você não sabe por quê? Este guia reúne os 7 cenários de erro mais comuns, um processo sistemático de diagnóstico em 5 etapas e soluções práticas para resolver 90% dos problemas em 5 a 10 minutos.
Parte 11 de 15
Próximo
Como adicionar busca com Pagefind a um blog Astro: guia completo, gratuito, rápido e com suporte a chinês
Aprenda passo a passo a adicionar busca de texto completo gratuita e rápida a um blog Astro com o Pagefind. Com suporte a chinês, índice inferior a 100 KB e configuração em 10 minutos, é uma alternativa mais econômica e simples ao Algolia.
Parte 13 de 15



Comentários
Entre com GitHub para comentar