A escolha de tecnologias não deve ser guiada pela aparência do currículo, mas sim pela resolução de problemas concretos.
Recentemente, conversei com um ex-colega que lidera uma equipe de front-end em uma startup. Em meio à conversa, ele me perguntou: "Estamos planejando reftaorar nosso projeto para Next.js e implementar Server-Side Rendering (SSR). O que você acha?"
Deixei meus talheres de lado e respondi: "Vocês estão enfrentando algum problema específico que justifique essa refatoração?"
Ele coçou a cabeça: "Na verdade, não temos problemas graves... Mas, ao procurar emprego, percebi que todos perguntam sobre experiência com Next.js. Se não usarmos, nossa stack pode parecer desatualizada."
"E o seu produto? Precisa de otimização para SEO? Como é o ambiente de rede dos seus usuários?", indaguei.
"Nossos usuários estão em cidades de primeira linha, com boa velocidade de internet. Quanto ao SEO, o produto exige login para uso, então os motores de busca não conseguem rastrear", ele respondeu.
Olhei para ele, sem saber o que dizer. Mais um colega influenciado pelas tendências tecnológicas.
SSR não é uma bala de prata, é uma espada de dois gumes
Nos últimos anos, frameworks como Next.js e Nuxt.js ganharam imensa popularidade. Comunidades de tecnologia estão repletas de posts como "Migramos de CSR para SSR e aumentamos o FCP em 50%" ou "SSR é o futuro do front-end".
No entanto, raramente vemos alguém detalhando os desafios que a equipe enfrentará ao longo de meses para alcançar essa melhoria de performance.
1. Custos de Servidor: De Gratuito a um Investimento
Páginas puramente estáticas, hospedadas em serviços como S3 ou Netlify, podem custar muito pouco, especialmente com baixo tráfego. Com SSR:
- Você necessita de um servidor dedicado ou instâncias de cloud functions.
- É preciso considerar a concorrência e implementar balanceamento de carga se um único servidor não for suficiente.
- A preocupação com a disponibilidade do servidor exige monitoramanto, alertas e estratégias de recuperação de falhas.
O projeto de um amigo, após adotar SSR, viu suas despesas mensais de nuvem saltarem de 300 para 3000. O chefe questionou se o aumento de velocidade era perceptível e se o custo adicional seria coberto pela receita. Ele não soube responder. Pior ainda, descobriu que a maioria dos usuários navegava da página inicial para detalhes, tornando a otimização da primeira renderização ineficaz para justificar o custo.
2. Transferência de Complexidade: De Front-end Puro para Full-stack
Em projetos CSR (Client-Side Rendering), o front-end foca na interface, e problemas de API são responsabilidade do back-end.
Com SSR:
// Abordagem anterior: simplicidade
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/user/${userId}`).then(response => response.json()).then(data => setUser(data));
}, [userId]);
return <div>{user?.name}</div>;
}
// Com SSR: complexidade surge
export async function getServerSideProps({ params }) {
try {
// Gestão de timeout de API
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);
const response = await fetch(`http://internal-api/user/${params.id}`, {
signal: controller.signal
}).catch(() => null); // Captura erros de rede
clearTimeout(timeoutId);
if (!response || !response.ok) {
// Estratégia de fallback?
return { props: { user: null, isFallback: true } };
}
const user = await response.json();
return { props: { user } };
} catch (error) {
// O que o usuário verá em caso de erro no servidor?
console.error("Server-side fetch error:", error);
return { notFound: true }; // Ou retornar um erro genérico
}
}
function UserProfile({ user, isFallback }) {
// Validação no cliente também é necessária
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
if (!isClient) {
// Previne erros de hidratação
return <div>Carregando...</div>;
}
// Verifica se o usuário existe após a hidratação
if (!user && !isFallback) {
return <div>Falha ao carregar perfil.</div>;
}
return <div>{user?.name}</div>;
}
Se a API falhar no servidor, qual a estratégia? Retornar erro 500 ou degradar para CSR? Como lidar com timeouts de API no servidor? Como sincronizar o estado entre servidor e cliente para evitar erros de hidratação?
Um colega que migrou para Next.js comentou: "Desde que adotei SSR, não escrevo apenas React, mas também configuro Nginx, entendo PM2 e depuro vazamentos de memória. Meu salário não aumentou, mas minhas responsabilidades dobraram." A maioria dos "likes" veio de outros desenvolvedores front-end.
3. Experiência de Desenvolvimento Fragmentada
No CSR, é comum usar window, document e localStorage livremente, pois tudo roda no navegador.
Com SSR:
// Antes, era simples
const browserWidth = window.innerWidth;
const authToken = localStorage.getItem('token');
const appHeight = document.getElementById('app').offsetHeight;
// Agora, requer cuidados
const browserWidth = typeof window !== 'undefined' ? window.innerWidth : 1024; // Valor padrão ou fallback
const authToken = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
const [appHeight, setAppHeight] = useState(0);
useEffect(() => {
setAppHeight(document.getElementById('app')?.offsetHeight || 0);
}, []);
- Bibliotecas de terceiros que não suportam SSR precisam ser importadas dinamicamente.
- Acesso direto a
localStorageousessionStoragenão é possível no servidor. - Navegação de rotas exige atenção, pois o servidor não possui o
historyAPI do navegador.
Lógicas antes triviais agora exigem código defensivo. É como passar por uma revista de segurança sem que a complexidade do negócio tenha mudado.
Você Realmente Precisa de SSR? Pergunet-se Três Questões Cruciais
Sempre que me perguntam sobre a adoção de SSR, peço que respondam a três perguntas. Na maioria das vezes, a própria reflexão os leva a desistir.
1. Seu Produto Depende de Motores de Busca?
Este é o critério mais objetivo e frequentemente usado como desculpa.
Se seu produto é:
- Um site de conteúdo (blog, notícias, institucional).
- Um e-commerce (páginas de produto precisam ser indexadas).
Então, SSR pode ser benéfico, pois crawlers podem ter dificuldade em executar JavaScript.
Porém, se seu produto é:
- Um sistema de administração que requer login.
- Uma H5 de ferramenta, jogo ou similar.
- Uma aplicação B2B SaaS.
- Uma versão H5 de um app social (onde o login é obrigatório).
Motores de busca não acessarão o conteúdo principal, tornando SEO uma necessidade artificial. Não use SEO como pretexto para adicionar Next.js ao seu currículo.
2. A Velocidade da Primeira Renderização é Realmente Inaceitável?
Muitas vezes, a lentidão percebida não é culpa do CSR, mas de código mal otimizado.
Analisei um projeto "lento" e descobri os seguintes problemas:
// Exemplo de código problemático
function App() {
const [data, setData] = useState(null);
const [user, setUser] = useState(null);
const [config, setConfig] = useState(null);
useEffect(() => {
// Chamadas sequenciais, uma esperando a outra
fetch('/api/data').then(res => res.json()).then(data => {
setData(data);
return fetch('/api/user');
}).then(res => res.json()).then(user => {
setUser(user);
return fetch('/api/config');
}).then(res => res.json()).then(setConfig);
// Imagem não otimizada
new Image().src = 'https://example.com/big-banner.png';
// Script de terceiros carregado de forma síncrona
const script = document.createElement('script');
script.src = 'https://analytics.com/sdk.js';
document.head.appendChild(script);
}, []);
return <div>...</div>;
}
Otimizar o código existente costuma ser mais vantajoso do que trocar toda a arquitetura.
No ano passado, otimizei um projeto Vue2 (CSR) que reduziu o tempo de carregamento da primeira renderização de 3.2s para 1.1s com apenas quatro mudanças:
// Após otimização
useEffect(() => {
// 1. Chamadas em paralelo
Promise.all([
fetch('/api/data'),
fetch('/api/user'),
fetch('/api/config')
]).then(([dataRes, userRes, configRes]) => Promise.all([dataRes.json(), userRes.json(), configRes.json()]))
.then(([data, user, config]) => {
setData(data);
setUser(user);
setConfig(config);
});
// 2. Imagens em WebP + lazy loading
// 3. Scripts de terceiros assíncronos
const script = document.createElement('script');
script.async = true;
script.src = 'https://analytics.com/sdk.js';
document.head.appendChild(script);
// 4. Code splitting para rotas
// const List = lazy(() => import('./pages/List')); // Exemplo com React.lazy
}, []);
Nenhuma mudança de arquitetura, refatoração massiva ou horas extras. Apenas código mais eficiente.
3. Sua Equipe Está Preparada?
Este é o fator mais negligenciado e a fonte de maior dor de cabeça após o lançamento.
Adotar SSR significa que sua equipe de front-end começará a escrever código de servidor:
- Alguém tem experiência com Node.js?
- Alguém sabe configurar Nginx?
- Alguém consegue diagnosticar vazamentos de memória?
# Um problema surge em produção, você sabe como agir?
curl -X POST https://seu-site.com/api/user -H "Content-Type: application/json" -d '{"id":123}'
# Se a resposta for 502 Bad Gateway:
# O processo Node.js caiu? Configuração do Nginx incorreta? Timeout da API interna?
# Acessando o servidor
ssh usuario@seu-servidor
pm2 logs # Verificar logs da aplicação
df -h # Disco cheio?
free -m # Vazamento de memória?
top # CPU sobrecarregado?
- Quem fará o rollback às 2 da manhã se algo der errado?
Se as respostas forem negativas, o dia do lançamento do SSR pode se tornar o início de um pesadelo para a equipe.
A escolha tecnológica deve considerar não apenas a "qualidade" da tecnologia, mas também a capacidade da equipe de adotá-la e mantê-la.
Alternativas Mais Atraentes que o SSR
Se você tem gargalos de performance, mas SSR não é a única solução, existem alternativas:
1. Static Site Generation (SSG)
Ideal para conteúdo estático ou que muda com pouca frequência.
// next.config.js (exemplo Next.js)
module.exports = {
// Gera HTML durante o build
exportPathMap: async function() {
return {
'/': { page: '/' },
'/sobre': { page: '/about' },
'/blog/1': { page: '/blog/[id]', query: { id: '1' } },
};
}
};
- HTML gerado no build, implantado em CDN.
- Performance de primeira renderização excelente e amigável para SEO.
- Sem custos de servidor ou manutenção operacional.
Next.js, Nuxt.js e VitePress suportam SSG. Você obtém os benefícios de performance do SSR com a simplicidade de implantação do CSR.
2. Implantação Estática + CSR
Na maioria dos cenários, esta é a abordagem ideal.
// index.html (exemplo)
<html>
<head>
<!-- Skeleton screen para feedback visual -->
<style>
.skeleton { background: #f0f0f0; height: 20px; margin: 10px; }
</style>
</head>
<body>
<div id="root">
<div class="skeleton"></div>
<div class="skeleton"></div>
<div class="skeleton"></div>
</div>
<!-- Recursos em CDN para carregamento paralelo -->
<link rel="preconnect" href="https://api.example.com">
<script src="https://cdn.example.com/react.js" async></script>
<script src="https://cdn.example.com/app.js" async></script>
</body>
</html>
- HTML hospedado em CDN para aceleração global.
- APIs acessadas via gateway ou BFF (Backend for Frontend).
- Combinado com pré-carregamento, lazy loading e skeleton screens, a experiência do usuário é excelente.
Meu projeto atual usa React + Vite, compilado para estático e hospedado em S3 com CDN. A primeira renderização leva 1.2s. Com milhões de page views mensais, os custos de servidor (apenas para o BFF) são inferiores a 500 reais. Use o que é suficiente, evite complexidade desnecessária.
3. SSR Parcial (Algumas Páginas SSR, a Maioria CSR)
Se apenas algumas páginas necessitam de SEO (landing pages, site institucional) e o restante requer login, você pode aplicar SSR seletivamente.
// next.config.js (exemplo Next.js)
module.exports = {
// Apenas estas extensões serão tratadas como páginas SSR
pageExtensions: ['ssr.js', 'page.js'],
async rewrites() {
return [
// Landing page usa SSR
{
source: '/',
destination: '/landing.ssr.js', // Apontando para o arquivo SSR
},
// Outras páginas usam CSR (arquivos HTML estáticos)
{
source: '/app/:path*',
destination: '/app.html', // Ou um proxy para o SPA
}
];
}
};
Next.js suporta o modo multi-página, e Vue oferece soluções para renderização híbrida. Não sobrecarregue 90% do seu projeto pela necessidade de 10%.
Considerações Finais: Escolha Tecnológica Pautada em Necessidade, Não em Glamour
Este artigo não visa desmerecer o SSR. É uma tecnologia valiosa quando aplicada ao contexto correto.
Contudo, critico a tendência de adoção sem critério: usar Next.js para uma simples página de evento H5, implementar SSR em um sistema de administração, ou buscar otimizar uma página de 1.5s para 1.2s.
Vale a pena sacrificar meses de manutenção da equipe por 0.3s de ganho? Os critérios para escolher uma tecnologia devem ser:
- Resolve nossos problemas atuais?
- A equipe tem capacidade para adotá-la e mantê-la?
- Os custos de manutenção são sustentáveis?
- O retorno sobre o investimento justifica o esforço?
Que a escolha tecnológica seja baseada em necessidades reais, não em uma performance para o currículo.
Compartilhe nos comentários: Que projetos "desnecessariamente SSR" você já viu? Quais armadilhas você encontrou?
Se você também se opõe a complexidade tecnológica sem propósito, siga-me para discutirmos o mundo real do front-end.