Otimização de imagens e assets no Next.js
1. Componente next/image e otimização automática
O Next.js oferece o componente Image como parte fundamental da estratégia de otimização de imagens. Este componente fornece otimização automática que inclui redimensionamento, conversão de formato e lazy loading nativo.
import Image from 'next/image';
export default function HeroBanner() {
return (
<div className="hero-container">
<Image
src="/images/banner-principal.jpg"
alt="Banner principal do site"
width={1200}
height={600}
priority
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
/>
</div>
);
}
O atributo priority desabilita o lazy loading para imagens acima da dobra, enquanto placeholder="blur" exibe uma versão miniatura borrada durante o carregamento. O Next.js converte automaticamente para formatos modernos como WebP e AVIF, baseando-se no suporte do navegador.
Para imagens responsivas, utilize o atributo sizes:
<Image
src="/images/produto.jpg"
alt="Produto em destaque"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="object-cover"
/>
2. Configuração avançada do next.config.js para imagens
O arquivo de configuração do Next.js permite controle granular sobre o processamento de imagens. Para imagens externas, configure domínios permitidos:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.unsplash.com',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'cdn.suaempresa.com',
port: '',
pathname: '/uploads/**',
},
],
deviceSizes: [640, 768, 1024, 1280, 1536],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
formats: ['image/avif', 'image/webp'],
minimumCacheTTL: 60,
},
};
module.exports = nextConfig;
Para usar um loader customizado como Cloudinary:
// lib/cloudinary-loader.js
export default function cloudinaryLoader({ src, width, quality }) {
const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`];
return `https://res.cloudinary.com/seu-cloud/image/upload/${params.join(',')}/${src}`;
}
// Uso no componente
import Image from 'next/image';
import cloudinaryLoader from '@/lib/cloudinary-loader';
<Image
loader={cloudinaryLoader}
src="v123456/sua-imagem.jpg"
alt="Imagem otimizada via Cloudinary"
width={800}
height={600}
/>
3. Otimização de fonts e CSS assets
O módulo next/font otimiza o carregamento de fontes com auto-subsetting e display=swap:
import { Inter, Roboto_Mono } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
});
const robotoMono = Roboto_Mono({
subsets: ['latin'],
display: 'swap',
variable: '--font-roboto-mono',
});
export default function Layout({ children }) {
return (
<html lang="pt-BR" className={`${inter.variable} ${robotoMono.variable}`}>
<body>{children}</body>
</html>
);
}
Para CSS, o Next.js suporta minificação automática via PostCSS. Configure plugins como cssnano para compressão adicional:
// postcss.config.js
module.exports = {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
},
};
4. Otimização de scripts e JavaScript bundles
O componente Script do Next.js oferece estratégias de carregamento inteligentes:
import Script from 'next/script';
export default function AnalyticsPage() {
return (
<>
<Script
src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
strategy="afterInteractive"
/>
<Script id="google-analytics" strategy="afterInteractive">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
`}
</Script>
</>
);
}
Para code splitting de componentes pesados:
import dynamic from 'next/dynamic';
const DynamicChart = dynamic(() => import('@/components/GraficoComplexo'), {
loading: () => <p>Carregando gráfico...</p>,
ssr: false, // Desabilita SSR para componentes client-side
});
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<DynamicChart />
</div>
);
}
Para análise de bundles:
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer(nextConfig);
Execute ANALYZE=true npm run build para visualizar o relatório interativo.
5. Cache e estratégias de entrega de assets
Configure headers de cache para assets estáticos:
// next.config.js
const nextConfig = {
async headers() {
return [
{
source: '/images/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
{
source: '/fonts/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
];
},
};
Para ISR com cache inteligente:
export async function getStaticProps() {
const data = await fetch('https://api.exemplo.com/produtos');
const produtos = await data.json();
return {
props: { produtos },
revalidate: 60, // Regenera a cada 60 segundos
};
}
6. Otimização de SVGs e ícones
Configure o Webpack para importar SVGs como componentes React:
// next.config.js
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
});
return config;
},
};
Uso otimizado de SVGs:
import IconeUsuario from '@/assets/icones/usuario.svg';
import IconeCarrinho from '@/assets/icones/carrinho.svg';
export default function Header() {
return (
<nav>
<IconeUsuario className="w-6 h-6" aria-hidden="true" />
<IconeCarrinho className="w-6 h-6" aria-hidden="true" />
</nav>
);
}
Para compressão de SVGs com SVGO:
// next.config.js
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: [
{
loader: '@svgr/webpack',
options: {
svgo: true,
svgoConfig: {
plugins: [
{ name: 'removeViewBox', active: false },
{ name: 'cleanupIDs', active: false },
],
},
},
},
],
});
return config;
},
};
7. Monitoramento e boas práticas de performance
Implemente monitoramento de Web Vitals:
// pages/_app.js
export function reportWebVitals(metric) {
console.log(metric);
if (metric.label === 'web-vital') {
// Envie para sua analytics
fetch('/api/vitals', {
method: 'POST',
body: JSON.stringify(metric),
});
}
}
Checklist final de otimização:
- Lazy Loading: Utilize
loading="lazy"(padrão nonext/image) para imagens abaixo da dobra - Formatos Modernos: Configure
formats: ['image/avif', 'image/webp']nonext.config.js - Cache Agressivo: Defina
Cache-Control: public, max-age=31536000, immutablepara assets estáticos - Compressão: Habilite compressão gzip/brotli no servidor ou CDN
- Acessibilidade: Sempre forneça
altdescritivo e contraste adequado
Use o Lighthouse e o modo Turbo do Next.js para testar:
next dev --turbo
Monitore métricas como LCP (deve ser < 2.5s), CLS (< 0.1) e FID (< 100ms) para garantir que suas otimizações estão funcionando conforme esperado.
Referências
- Documentação oficial do next/image — Guia completo sobre o componente Image e suas configurações de otimização
- Next.js Image Optimization Documentation — Documentação detalhada sobre otimização de imagens no Next.js
- Web.dev - Optimize images in Next.js — Tutorial prático do Google sobre otimização de imagens com Next.js
- Vercel - Image Optimization Guide — Guia oficial da Vercel sobre otimização de imagens e CDN
- Next.js Font Optimization — Documentação sobre otimização de fontes com next/font
- Bundle Analyzer for Next.js — Pacote para análise de bundles JavaScript no Next.js
- SVGR Webpack Integration — Guia de integração do SVGR com Next.js para otimização de SVGs