Site lento por JavaScript: como identificar e reduzir o peso
Imagens e fontes carregam-se otimizam-se com plugins. JavaScript, não. JavaScript é o problema que sobra depois de tudo o resto resolvido — e em 2026 é o maior responsável por sites lentos em mobile, scores baixos no PageSpeed, e INP acima de 200ms.
Este guia ataca o problema: como descobrir o que está a pesar, como reduzir sem partir funcionalidade, e como evitar que volte a crescer.
Porque é que o JavaScript dói mais do que as imagens
Uma imagem pesada custa bandwidth — demora a descarregar. Mas depois de descarregada, não pesa mais.
JavaScript custa três coisas:
- Descarga — bytes a transferir.
- Parse + compile — o navegador tem de interpretar e converter em código executável (custa CPU).
- Execução — corre. Bloqueia a main thread. Atrasa interação.
Em telemóveis de gama média (Android 200-400€, que é o que a maioria dos clientes em Portugal usa), 500 KB de JavaScript pode demorar 3-5 segundos a parse+execute. A página visualmente "está lá" mas não responde a clicks. É exatamente isso que o Google mede em INP.
Diagnosticar: as 3 ferramentas que importam
PageSpeed Insights — o resumo
Vai a pagespeed.web.dev com o teu URL. Procura especificamente:
- "Reduce unused JavaScript" — quanto código foste obrigado a descarregar e nunca foi executado.
- "Eliminate render-blocking resources" — scripts no
<head>semdefer/async. - "Minimize main-thread work" — quanto tempo a CPU passou só com JavaScript.
- "Reduce JavaScript execution time" — o que executou e quanto demorou.
Se algum destes ultrapassa 1.5s em mobile, tens problema sério. Detalhe completo no guia do PageSpeed Insights.
Chrome DevTools → Coverage
Abre o teu site no Chrome. F12 → Cmd+Shift+P → "Show Coverage". Recarrega. Para cada ficheiro JS verás quanto código foi carregado vs quanto foi realmente executado. Razão típica em sites de PME: 70-90% de JS não usado.
Chrome DevTools → Performance
Grava 5 segundos de carregamento. Procura as "Long Tasks" (tarefas >50ms) na main thread. Cada uma é um momento em que o utilizador clicou e nada aconteceu. Identifica que script as causa.
Os 7 culpados mais comuns
Em centenas de auditorias a sites WordPress de PME portuguesa, os mesmos suspeitos voltam:
- Google Tag Manager mal configurado — carrega 30 tags em vez das 5 necessárias.
- Plugins de slider (Revolution Slider, Smart Slider) — 200-500 KB por slider, mesmo onde não há slider.
- Plugins de chat (Tawk, Tidio, Crisp) — carregam síncronos no head.
- Page builders (Elementor, WPBakery) — JS para animações que ninguém pediu.
- Form builders pesados (WPForms premium, Gravity Forms com 12 add-ons).
- Bibliotecas duplicadas — tema carrega jQuery 1.x, plugin carrega jQuery 3.x.
- Tracking scripts sem consentimento gated (Meta Pixel, Hotjar, Clarity) a competir por main thread.
A boa notícia: identificar cada um leva 5 minutos com Chrome DevTools. Cortar cada um vale 100-500ms.
Defer vs async vs nada
Por defeito, um <script src="..."> no HTML bloqueia o navegador — pára de renderizar até descarregar e executar. Os atributos resolvem isso:
<!-- Bloqueia. Evitar. -->
<script src="grande.js"></script>
<!-- Descarrega em paralelo, executa logo que descarregado (pode interromper) -->
<script src="analytics.js" async></script>
<!-- Descarrega em paralelo, executa só depois do HTML pronto -->
<script src="ui.js" defer></script>
Regras práticas:
deferpara scripts da página (UI, formulários). Mantém ordem de execução.asyncpara scripts independentes que não dependem nem afetam o resto (analytics, pixels).- Sem atributo só para scripts realmente críticos acima da dobra (raríssimo).
Em WordPress, plugins como Autoptimize ou Async JavaScript automatizam isto. Em Next.js, a tag <Script> tem strategy="afterInteractive" ou "lazyOnload".
Tag Manager: o assassino silencioso
Google Tag Manager é prático, mas vira pesadelo rápido. Cada tag adicional é JavaScript de terceiros a competir por main thread.
Auditoria mínima a fazer uma vez por trimestre:
- Abre o GTM. Lista todas as tags ativas.
- Para cada uma, pergunta: ainda usamos esta? Há quanto tempo?
- Apaga as inativas/desconhecidas. A maioria das contas tem 40% de tags mortas.
- Verifica triggers — tags a disparar em "All Pages" quando deviam estar em páginas específicas.
- Move o GTM para gated por consentimento de cookies (RGPD + performance).
Resultado típico: GTM passa de 250 KB de overhead para 80 KB. INP cai 100ms.
Plugins WordPress: matar primeiro, fazer cocó depois
Métrica simples: cada plugin ativo custa, em média, 30-80 ms de TTFB e 20-150 KB de JS/CSS frontend. Multiplica por 25 plugins (típico) e tens 1-2 segundos de custo.
Tratamento:
- Listar todos os plugins. Para cada um, classificar: essencial / útil / esquecido.
- Desativar os esquecidos. Se não notas nada 7 dias, apaga.
- Substituir os pesados por leves. Slider Revolution → Swiper.js direto (10x mais leve). Contact Form 7 com add-ons → WPForms Lite ou um custom.
- Lazy load de scripts não-críticos com plugin como FlyingScripts.
Lazy load de JavaScript de terceiros
Scripts como chat widgets, mapas embedded, players de vídeo, podem esperar pela primeira interação:
// Pseudo-código: carrega o chat só depois do utilizador interagir
['scroll', 'mousemove', 'touchstart'].forEach(e =>
document.addEventListener(e, loadChat, { once: true })
);
Plugins WordPress como FlyingScripts ou Perfmatters fazem isto sem código. Resultado: o LCP cai imediatamente, e o chat continua a aparecer quando o utilizador interage.
Code splitting (para sites custom)
Para Next.js, React, ou framework moderno, o code splitting acontece automaticamente — cada página carrega só o JS dessa rota. Mas há erros comuns:
- Importar bibliotecas pesadas no
_app.tsx(vai para todas as páginas). - Usar
importem vez dedynamic importpara módulos só usados em modais. - Não tree-shake bibliotecas (importar
lodashinteiro em vez delodash/get).
next/dynamic resolve estes em 5 minutos.
Métricas-alvo realistas
Para PME portuguesa típica em 2026:
| Métrica | Bom | Aceitável | Mau |
|---|---|---|---|
| Total JS (transfer) | < 200 KB | 200-400 KB | > 400 KB |
| Tempo execução JS (mobile) | < 1s | 1-2s | > 2s |
| Long tasks | 0-2 | 3-5 | > 5 |
| INP (p75) | < 200 ms | 200-500 ms | > 500 ms |
Sites WordPress com Elementor + 5 plugins de marketing tendem a ficar na coluna "mau" sem esforço. Sites custom bem feitos ficam no "bom" sem esforço.
O que NÃO fazer
- Minificar não é otimização. Reduz ~20% de bytes mas não muda parse+execute. Faz-se mas não conta como solução.
- Não acreditar em plugin de "cache" mágico. Cache HTML serve a página pronta — não reduz JS no browser do utilizador.
- Não substituir GTM por "tags hardcoded no tema". Perdes controlo, ganhas marginalmente.
- Não migrar para framework "rápido" sem identificar o problema. Se o problema é Elementor + 5 chat widgets, mudar para Next.js sem mudar o resto piora.
Service Workers — vale a pena?
Service Workers (a base das Progressive Web Apps) permitem cachear JS no browser para visitas repetidas. Para um site institucional, o ganho é marginal — utilizadores típicos visitam uma vez por mês.
Para lojas online com utilizadores que voltam várias vezes por semana, faz diferença: o JS principal já está em cache local na segunda visita, TTFB para "carregar a app" cai a 0ms.
Em WordPress, plugins como PWA for WP simplificam. Em Next.js, next-pwa cobre o caso. Para PME pequena, vai à frente das tuas necessidades. Para loja com 5.000 visitantes/mês, considera.
Métrica em campo vs em laboratório
Quando otimizas JS, há duas realidades:
- Lab (Lighthouse, PageSpeed Insights) — simula CPU 4x slower e rede 3G. Conservador. Bom para detetar regressões em PR.
- Field (CrUX, RUM próprio) — visitantes reais com hardware real. É o que o Google rankeia.
Diferenças típicas: Lab diz INP 350ms. Campo diz INP 220ms (utilizadores reais têm dispositivos médios variados, alguns em desktop). Não confundas: otimiza para Lab passar limites, mas valida em campo antes de declarar vitória.
O ciclo de auditoria recomendado
Para PME que quer manter performance ao longo do tempo, não basta otimizar uma vez. Recomendação:
- Mensal — verificar Search Console Core Web Vitals. Se grupo de páginas piorou, investigar.
- Trimestral — auditoria de plugins WordPress: o que se acrescentou? O que se pode tirar?
- Semestral — Tag Manager: lista de tags ativas, comparar com o que se está mesmo a usar.
- Anual — auditoria completa: PageSpeed em 5 páginas-chave, comparar com ano anterior.
Sem este ciclo, sites bem otimizados degradam-se em 12-18 meses. Plugins acumulam, tags adicionam-se, ninguém limpa.
Em resumo
JavaScript pesado é hoje a maior causa de sites lentos em mobile e de INP fora dos limites. O problema é cumulativo: GTM com tags mortas, plugins esquecidos, sliders gigantes, chats síncronos, bibliotecas duplicadas. Diagnostica com PageSpeed Insights + Chrome DevTools Coverage (vais ver 70-90% de código não usado). Ataca em camadas: defer/async no que sobra, lazy load em scripts de terceiros, auditoria trimestral do Tag Manager, e substituição de plugins pesados por alternativas leves. Alvo realista para PME: <200 KB de JS, <1s de execução em mobile, INP <200ms. Maioria dos sites lá chega com 4-8 horas de trabalho — não com refactor de meses.
No sitesfixe.pt entregamos sites com JS auditado por defeito — defer/async corretos, sem bibliotecas duplicadas, com tracking gated por consentimento. Se o teu site WordPress tem INP acima de 500ms e ninguém sabe porquê, fala connosco. Sites desde 1.500€.
Lê também:
Fontes
Precisas de um site ou loja online?
Agência digital portuguesa. Sites e lojas online rápidos, otimizados para o Google e feitos para resultado.
Pedir orçamento