Quem domina as ferramentas resolve em minutos o que os outros levam um dia

Apostila completa de DevTools & Ferramental de Debug

Depurar não é espalhar console.log e torcer. É um método — reproduzir, isolar, formular hipótese, testar — apoiado por ferramentas que mostram o estado real do sistema: o DOM, a rede, a memória, a pilha de chamadas, o perfil de CPU. Esta apostila ensina o DevTools do browser a fundo, o debugger do editor e do Node, os DevTools de frameworks, e o ferramental de rede, bundle e diagnóstico — com o olho no que empresas esperam de um dev que "sabe se virar".

10 módulosElements · Console · Sources · NetworkPerformance · Memory · Web VitalsVS Code · Node --inspect · React DevToolsBoxes de entrevistaExercícios com gabarito
MÓDULO 01 · BÁSICO

Depuração como método

Objetivo: transformar "depurar" de tentativa-e-erro num processo repetível — reproduzir, isolar, hipótese, testar — e entender por que console.log às cegas é o caminho lento.

1.1 O método científico aplicado a bugs

 1. REPRODUZIR   ── consigo fazer o bug acontecer de forma consistente?
                    (passos exatos, dados exatos, ambiente exato)
 2. ISOLAR       ── qual a MENOR parte do sistema que ainda exibe o bug?
                    (remover metade de cada vez — bisseção)
 3. HIPÓTESE     ── "acho que é X porque Y". Uma afirmação FALSIFICÁVEL.
 4. TESTAR       ── um experimento que confirma OU refuta a hipótese.
                    (não vários ao mesmo tempo)
 5. ── confirmou? conserte, e escreva um TESTE que reproduz (não repete)
    ── refutou?   volte ao passo 3 com o que aprendeu
💡 Uma variável por vez

O erro nº 1 ao depurar sob pressão é mudar cinco coisas, o bug sumir, e você não saber qual resolveu (nem se voltará). Mude uma coisa, observe, reverta se não ajudou. É lento? Não — é o caminho rápido; o caminho lento é o "chute → chute → chute" que às vezes esconde o bug em vez de corrigi-lo.

1.2 Reprodução mínima

Um bug que só acontece "às vezes, na produção, com esse cliente" é quase impossível de corrigir. O trabalho é reduzi-lo a uma reprodução mínima e determinística: o menor código/estado/passos que ainda falha. Benefícios: você entende a causa no processo de reduzir; fica trivial de testar a correção; e vira um caso de teste. Ferramentas: codesandbox/stackblitz para front, um script isolado para back, um curl para uma API.

1.3 console.log vs o debugger

console.log espalhadoBreakpoint / debugger
Você adivinha onde olhar e o quê imprimir; erra, adiciona mais, recarregaPara no ponto e você inspeciona tudo — variáveis locais, escopo, this, call stack — sem prever
Ciclo: editar → salvar → recarregar → ler o consoleCiclo: pausou → olhou → seguiu (step) — sem recompilar
Fica no código (você esquece um em produção)Não toca o código; logpoint imprime sem editar o arquivo
Útil para: fluxo em produção, timing, loops muito rápidos, logs estruturadosÚtil para: entender estado, condições, "por que entrou/não entrou aqui"

console.log tem lugar (Módulo 2 mostra como usá-lo bem), mas se a sua ferramenta principal é adicionar console.log, recarregar e ler — você está deixando 80% do poder do DevTools na mesa.

1.4 Outras técnicas que economizam horas

💼 Mercado de trabalho

Entrevistas de debugging existem (às vezes ao vivo, com um bug plantado). Avaliam o processo: você reproduz antes de mexer? forma hipóteses testáveis? usa o debugger ou só console.log? isola em vez de chutar? Descrever o método (reproduzir → isolar → hipótese → testar → teste de regressão) já sinaliza senioridade. "Eu ia colocando console.log até achar" é resposta de júnior.

✏️ Exercício 1 — Estruture a investigação

"O botão de salvar não funciona para alguns usuários." É tudo que você tem. Escreva as 5 primeiras perguntas/passos, em ordem.

Gabarito (exemplo): (1) Reproduzir: consigo fazer acontecer? Com qual conta, qual dado, qual navegador, qual passo exato? Se não reproduz, coletar do usuário: vídeo, console, network (HAR), navegador/SO. (2) Delimitar "não funciona": o clique não dispara nada? dispara e dá erro? salva mas some? — abrir o DevTools: Console tem erro? Network mostra a request? Qual status? (3) Isolar a fatia de usuários: o que "alguns usuários" têm em comum? plano, permissão, feature flag, região, dado grande, caractere especial, timezone? (4) Hipótese falsificável: ex. "falha quando o campo X tem mais de N caracteres e o backend retorna 422". (5) Testar: reproduzir com esse dado específico; olhar a resposta da API no Network; confirmar. Depois: corrigir + teste de regressão com o caso.

MÓDULO 02 · BÁSICO

DevTools — Elements & Console

Objetivo: inspecionar e editar o DOM e o CSS ao vivo, entender o box model e a especificidade no painel, e usar o Console como um REPL poderoso — não só como "onde os logs aparecem".

2.1 Abrir e navegar

2.2 Elements: DOM e CSS ao vivo

2.3 O Console como REPL

// helpers que só existem no Console:
$0            // o elemento selecionado agora no painel Elements ($1 = o anterior, etc.)
$('.btn')      // = document.querySelector('.btn')   (só no Console, não é jQuery)
$$('li')       // = [...document.querySelectorAll('li')]  (array de verdade)
$x('//a[@href]') // consulta por XPath

inspect($0)             // abre o elemento/objeto no painel apropriado
getEventListeners($0)   // os listeners do elemento, como objeto
copy(objetoOuTexto)     // copia para o clipboard (ótimo p/ um JSON grande)
monitorEvents($0, 'click')   // loga cada evento; unmonitorEvents($0) para parar
monitor(minhaFn)              // loga cada chamada da função e seus argumentos
queryObjects(Promise)        // todas as instâncias vivas de um construtor
MétodoPara quê
console.table(arr)Array de objetos como tabela ordenável — muito melhor que log
console.dir(el)Um elemento DOM como objeto (propriedades) em vez de como HTML
console.group() / groupEnd()Agrupar logs relacionados (recolhível)
console.assert(cond, msg)Loga só se a condição for falsa
console.count(label) / countResetQuantas vezes esta linha foi executada
console.time(l) / timeEnd(l)Medir a duração de um trecho
console.trace()Imprime o stack trace de como chegou aqui
%c em console.log('%ctexto', 'color:red')Estilizar a saída
⚠️ Objetos são "vivos" no Console

Quando você faz console.log(obj) e clica para expandir depois, o DevTools mostra o estado do objeto no momento da expansão, não do log — se ele mudou nesse meio-tempo, você vê o valor novo e se confunde. Para congelar: console.log(structuredClone(obj)) ou console.log(JSON.parse(JSON.stringify(obj))), ou console.table.

💼 Mercado de trabalho

Perguntas/tarefas ao vivo: "Por que este elemento está com essa cor/margem? mostre no DevTools" (Computed → de qual regra veio; ou Styles), "O que é $0?", "Como você lista todos os event listeners de um botão?" (aba Event Listeners ou getEventListeners($0)), "Como você inspeciona um estado :hover?" (forçar em :hov). Fluência aqui é esperada de qualquer front-end.

✏️ Exercício 2 — Investigue no Elements

Um link deveria ser azul e sublinhado, mas aparece preto e sem sublinhado. Descreva os passos no DevTools para descobrir por quê, sem tocar no código-fonte.

Gabarito: (1) Ctrl/Cmd+Shift+C e clicar no link → ele fica selecionado no Elements. (2) Aba Styles: procurar as regras que setam color e text-decoration; a que vence está no topo sem risco. Provavelmente há um a { color: inherit; text-decoration: none } (reset de design system) mais específico ou depois. (3) Aba Computed: expandir color e text-decoration-line → o DevTools mostra a regra exata e o arquivo:linha de origem. (4) Testar a hipótese: no bloco element.style, adicionar color: blue; text-decoration: underline — se resolver, confirma que era só o CSS sendo sobrescrito. (5) Conclusão: a correção é aumentar a especificidade da regra do link ou ajustar o reset — mas o diagnóstico saiu 100% do painel.

MÓDULO 03 · INTERMEDIÁRIO

DevTools — Sources e breakpoints

Objetivo: parar o código no ponto certo com os vários tipos de breakpoint, inspecionar a pilha e o escopo, e usar source maps, blackboxing, snippets e local overrides.

3.1 O painel Sources

3.2 Os tipos de breakpoint

TipoComoQuando
De linhaClicar no número da linha (ou debugger; no código)Parar toda vez que passar ali
CondicionalBotão direito na linha → Add conditional breakpoint → id === 42Loop com 5.000 iterações e só a 4.999ª te interessa
LogpointBotão direito → Add logpoint → 'valor', x, objQuer o efeito do console.log sem editar o arquivo nem parar
DOMNo Elements, botão direito no nó → Break on → subtree modifications / attribute modifications / node removal"Quem está mexendo neste elemento?" — para no JS que causou a mutação
XHR/fetchPainel Sources → XHR/fetch Breakpoints → + → um pedaço da URLPara logo antes de uma requisição sair — vê a stack de quem a disparou
Event ListenerSources → Event Listener Breakpoints → marcar "click", "keydown", "load"…"O que roda quando o usuário clica/pressiona X?"
ExceptionsBotão ⏸ com o octógono → "Pause on uncaught exceptions" (e opcionalmente "caught")Para no momento em que o erro é lançado, com o estado intacto

3.3 Controlar a execução

AçãoAtalhoFaz
ResumeF8Continua até o próximo breakpoint
Step overF10Executa a linha; não entra em funções chamadas
Step intoF11Entra na função chamada na linha atual
Step outShift+F11Roda até sair da função atual
Deactivate breakpointsCtrl/Cmd+F8Ignora todos temporariamente sem apagá-los

3.4 Source maps

Seu código roda como um bundle minificado (app.a3f9.js), mas você escreveu TypeScript/JSX. O source map (.map) mapeia cada posição do bundle para o arquivo/linha/coluna original — o DevTools mostra e depura o seu código. Garanta que o build gera source maps (em dev sempre; em produção, considere hidden source maps enviados só ao Sentry). Se você vê código minificado no debugger, o source map não carregou (404, caminho errado, ou desligado).

3.5 Recursos que economizam tempo

💼 Mercado de trabalho

Perguntas: "Diferença entre step over e step into", "Como você para o código só quando x === 42?" (conditional breakpoint), "Um elemento some da tela e você não sabe qual código removeu — como descobre?" (DOM breakpoint em "node removal"), "Como depurar só o seu código ignorando as libs?" (blackboxing/ignore list), "Você vê código minificado no debugger — o que houve?" (source map não carregou). Saber logpoint e conditional breakpoint em vez de editar o arquivo é sinal de fluência.

✏️ Exercício 3 — "Uma request errada está saindo"

A aba Network mostra uma chamada POST /api/track com um corpo estranho, e você não sabe de onde ela vem. Descreva como achar o código responsável.

Gabarito: (1) Sources → XHR/fetch Breakpoints → + → digitar /api/track. (2) Reproduzir a ação → o debugger pausa no momento em que a request vai sair. (3) Olhar o Call Stack — o frame de cima é quem chamou fetch; descer pelos frames revela a cadeia (um handler de clique? um useEffect? um SDK de analytics?). Se houver muito ruído de biblioteca, adicionar os arquivos das libs à ignore list para o stack ficar só com o seu código. (4) No Scope/Console do frame, inspecionar os argumentos passados ao fetch para ver como o corpo estranho foi montado. (5) Alternativa: na aba Network, coluna Initiator já mostra a stack resumida da origem da request — às vezes basta.

MÓDULO 04 · INTERMEDIÁRIO

DevTools — Network

Objetivo: ler o waterfall e o timing de cada request, simular condições de rede, bloquear e reproduzir requisições, e exportar para investigação.

4.1 A tabela e o waterfall

4.2 Detalhes de uma request

Clique numa linha:

4.3 Ferramentas de reprodução e teste

Ação (botão direito na request)Uso
Copy → Copy as cURL / as fetch / as PowerShellReproduzir a request exata no terminal ou colar num arquivo — com todos os headers e cookies
Copy → Copy responsePegar o JSON de resposta para inspecionar/mockar
Replay XHRRe-disparar a mesma request a partir do DevTools
Block request URL / domainSimular a falha de um recurso (um script de terceiro, uma API) e ver como a página se comporta
Override content (via Local Overrides)Substituir a resposta de uma API por um JSON seu, sem backend — testar estados de erro/vazio
Save all as HARExportar toda a sessão de rede (um .har) para anexar a um bug, ou importar de volta / analisar em outra ferramenta. Contém cookies e tokens — trate como sensível

4.4 Throttling

4.5 WebSockets, SSE e outros

💼 Mercado de trabalho

Perguntas: "O que significa TTFB alto?" (o servidor demorou a começar a responder — backend ou rede, não o download), "Como você reproduz uma request da aba Network no terminal?" (Copy as cURL), "Como testar como a página reage se uma API cai?" (Block request, ou override da resposta com um erro), "O que 'Preserve log' resolve?" (depurar fluxos com redirect/navegação), "Como exportar a rede para um bug report?" (HAR — e cuidado, tem tokens).

✏️ Exercício 4 — Página lenta ao carregar

Uma página demora ~6s para ficar utilizável. Descreva o que você olha na aba Network para diagnosticar.

Gabarito: (1) Recarregar com Disable cache e o Network aberto; ordenar por Time ou olhar o Waterfall. (2) Identificar o gargalo: uma request com Waiting (TTFB) enorme = backend lento numa API crítica no caminho. Requests grandes em Size = bundle/imagem sem otimização (comprimir, code-split, lazy). Muitas requests em série (cada uma começa quando a anterior termina) = waterfall de dependências — paralelizar/pré-carregar. (3) Ver a linha do DOMContentLoaded (azul) e Load (vermelha) no waterfall: o que acontece depois delas e ainda bloqueia o "utilizável". (4) Filtrar por Type: Doc/JS/CSS para achar recursos render-blocking. (5) Cruzar com o painel Performance (Módulo 5) para ver se é rede ou execução de JS (main thread travada). (6) Initiator das requests tardias: alguma é disparada por um script de terceiro pesado que dá para adiar?

MÓDULO 05 · INTERMEDIÁRIO

DevTools — Performance e Web Vitals

Objetivo: gravar e ler um profile de performance — flame chart, main thread, long tasks, layout/paint — e medir as Core Web Vitals (LCP, INP, CLS) dentro do DevTools.

5.1 As Core Web Vitals

MétricaMedeBom
LCP (Largest Contentful Paint)Quando o maior elemento de conteúdo aparece — a percepção de "carregou"≤ 2,5 s
INP (Interaction to Next Paint)A latência da pior interação (clique/tecla) até a tela atualizar — a percepção de "responde"≤ 200 ms
CLS (Cumulative Layout Shift)Quanto o conteúdo "pula" durante o carregamento≤ 0,1

No DevTools: o painel Performance mostra LCP/CLS numa gravação; a seção "Live Metrics" (Performance, versões recentes) mede LCP, CLS e INP enquanto você usa a página; a extensão Web Vitals mostra num overlay. Lembre: o número que o Google usa (CrUX) vem de usuários reais — o do seu laptop é só indicativo.

5.2 Gravar um profile

  1. Painel Performance → escolher CPU throttling (4× ou 6× para simular celular) e Network throttling se o foco é carregamento.
  2. Para carregamento: botão de reload (⟳) grava desde o início. Para uma interação: Record → fazer a ação → Stop. Mantenha curto (poucos segundos).

5.3 Ler o profile

5.4 Os problemas clássicos e o que procurar

Sintoma no profileCausa provável
Bloco amarelo largo antes do primeiro paintJS pesado bloqueando o render (bundle grande, parse/compile, trabalho síncrono no boot)
Muitos blocos roxos "Recalculate Style" / "Layout"Layout thrashing: ler layout (offsetHeight) e escrever estilo em loop, forçando reflows sucessivos
"Layout" gigante ocasionalMudança que afeta muitos elementos (uma classe no <body>)
Long tasks durante o scroll/digitaçãoHandler pesado; falta de debounce/throttle; render de lista sem virtualização
Paint frequente numa área grandeAnimar propriedades que causam paint/layout (top, width) em vez de transform/opacity; ligar "Paint flashing" no painel Rendering
CLS: elemento pula quando uma imagem/fonte carregaSem width/height ou aspect-ratio na imagem; injeção de banner acima do conteúdo; font-display
💡 Meça, não adivinhe

"Acho que este componente está lento" não é dado. Grave o profile, ache o bloco largo, olhe o Self Time no Bottom-Up. Frequentemente o culpado não é o que você imaginava (é um JSON.parse de 2 MB, um date-fns chamado 10.000 vezes num render, uma lib de terceiro). Otimize o que o profiler aponta; re-meça para confirmar o ganho.

💼 Mercado de trabalho

Perguntas: "O que são LCP, INP e CLS?", "Como você investiga uma página que trava ao digitar?" (Performance → gravar a interação → long tasks no Main → Bottom-Up por Self Time), "O que é layout thrashing e como aparece no profile?", "Por que animar transform e não top?" (evita layout/paint; fica no compositor), "Diferença entre Self Time e Total Time". Cruza com a apostila de CSS Avançado e de Observabilidade.

✏️ Exercício 5 — Jank ao abrir um menu

Ao clicar num botão que abre um menu suspenso com ~200 itens, a UI congela por ~400 ms. Descreva a investigação e as hipóteses.

Gabarito: (1) Performance → CPU throttling 4× → Record → clicar no botão → Stop. (2) Achar a long task logo após o evento de clique no Main. (3) Olhar o flame chart: um bloco largo de Scripting = construir/renderizar os 200 itens de uma vez (React reconciliando 200 nós, ou criar 200 elementos DOM em loop). Um bloco largo de Layout/Recalculate Style depois = inserir os 200 no DOM força um reflow grande, talvez agravado por CSS custoso (sombras, filtros) por item. (4) Bottom-Up por Self Time confirma quem gasta. Hipóteses/correções: virtualizar a lista (renderizar só os ~15 visíveis — react-window/@tanstack/virtual); adiar a montagem (abrir o container vazio e preencher em requestIdleCallback ou em chunks); simplificar o CSS por item; memoizar. Re-gravar para confirmar que a long task sumiu.

MÓDULO 06 · AVANÇADO

DevTools — Memory, Application e o resto

Objetivo: caçar vazamentos de memória com heap snapshots e allocation timeline, inspecionar storage/service workers/cache no painel Application, e conhecer Lighthouse, Coverage, Rendering, Animations e o painel Issues.

6.1 Memory — vazamentos de JS

Um memory leak no front: objetos que deveriam ser coletados continuam referenciados, e a heap cresce sem parar (a aba fica lenta, trava, ou o navegador mata a página). Ferramentas do painel Memory:

FerramentaUso
Heap snapshotUma "foto" de toda a memória JS. Tire uma, faça a ação suspeita N vezes (abrir/fechar um modal, navegar entre rotas), tire outra, e compare (modo Comparison): o que cresceu e não foi liberado é o vazamento. Procure "Detached" (nós DOM sem pai mas ainda referenciados por JS) e a coluna "Retained Size"
Allocation instrumentation on timelineGrava as alocações ao longo do tempo; barras azuis que não ficam cinza (não foram liberadas) apontam o código que aloca e retém
Allocation samplingBaixo overhead; mostra qual função alocou mais memória num período — bom para produção-like
💡 O fluxo de caça a leak (three-snapshot)

(1) Snapshot A. (2) Executar a ação suspeita ~10×, forçar GC (ícone de lixeira). (3) Snapshot B. (4) Ação ~10× de novo + GC. (5) Snapshot C. (6) No snapshot C, filtrar "Objects allocated between A and B" — o que sobreviveu duas rodadas de GC é quase certamente o leak. Causas típicas: addEventListener sem removeEventListener, timers (setInterval) nunca limpos, closures que capturam um objeto grande, caches/arrays globais que só crescem, e — em React — useEffect sem cleanup ou listeners registrados fora do ciclo.

6.2 Application — o estado do lado do cliente

6.3 Lighthouse

Aba Lighthouse: auditoria automatizada de Performance, Accessibility, Best Practices e SEO, com nota (0–100) e recomendações acionáveis ("elimine recursos que bloqueiam o render", "imagens sem dimensões", "contraste insuficiente"). Rode em modo incognito (extensões distorcem) e várias vezes (há variância). É um ponto de partida: a nota de Performance vem de uma simulação; use o painel Performance para o diagnóstico real, e o teste manual para acessibilidade (ver apostila de Acessibilidade & WCAG). Existe Lighthouse CI para gate no pipeline.

6.4 Coverage

Command Menu → "Show Coverage" → recarregar → mostra, por arquivo, quanto do CSS e JS foi realmente executado vs carregado. Barras vermelhas = código morto naquele carregamento — candidatos a code-splitting, lazy loading, ou remoção. Não é "cobertura de testes" — é "quanto do bundle a página usou".

6.5 Rendering

Command Menu → "Show Rendering". Ferramentas de diagnóstico visual:

6.6 Outros painéis úteis

💼 Mercado de trabalho

Perguntas: "Como você confirma e localiza um memory leak no front?" (heap snapshots comparados / three-snapshot; procurar Detached nodes e listeners/timers não limpos), "Minha alteração não aparece por mais que eu recarregue — o que pode ser?" (service worker no cache; Application → Update on reload / Bypass; ou cache HTTP), "Para que serve a aba Coverage?" (código não usado no carregamento → code-splitting), "Como testar dark mode / reduced-motion sem mexer no SO?" (Rendering → Emulate).

✏️ Exercício 6 — SPA que fica lenta com o tempo

Um app de dashboard fica progressivamente lento conforme o usuário navega entre as telas durante o dia, até travar. Descreva a investigação.

Gabarito: Cheira a memory leak acumulado a cada navegação de rota. (1) Painel Memory: three-snapshot — snapshot A na tela X; navegar X→Y→X ~10 vezes + forçar GC; snapshot B; repetir; snapshot C. (2) No snapshot final, ordenar por Retained Size e procurar: nós Detached (componentes desmontados cujo DOM ainda é referenciado), instâncias de componentes/stores que crescem em contagem, arrays/Maps que só aumentam. (3) Clicar num objeto suspeito → painel Retainers mostra quem o segura vivo (a cadeia de referências). Causas típicas num dashboard: setInterval de polling não limpo no unmount, addEventListener global (resize/scroll) sem remove, subscrições (WebSocket, event bus, RxJS) sem unsubscribe, cache de dados por rota que nunca expira, ou uma lib de gráfico que não faz destroy(). (4) Verificar no código os useEffect/ngOnDestroy/onUnmounted correspondentes. (5) Corrigir os cleanups, repetir o three-snapshot e confirmar que a heap volta ao baseline após GC.

MÓDULO 07 · AVANÇADO

Debuggers fora do browser

Objetivo: usar o debugger do editor (VS Code) com launch.json, depurar Node.js com --inspect e o DevTools, e conhecer os equivalentes em outras stacks.

7.1 O debugger do VS Code

O mesmo poder do DevTools (breakpoints, step, watch, call stack, debug console) dentro do editor, para backend, scripts, testes e — via extensões — frontend. Configura-se em .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug API",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/src/server.ts",
      "runtimeArgs": ["--import=tsx"],
      "envFile": "${workspaceFolder}/.env",
      "console": "integratedTerminal"
    },
    {
      "name": "Attach to :9229",
      "type": "node",
      "request": "attach",
      "port": 9229
    },
    {
      "name": "Debug current test",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/node_modules/.bin/vitest",
      "args": ["run", "${relativeFile}"],
      "console": "integratedTerminal"
    }
  ]
}

7.2 Node.js: --inspect

node --inspect app.js            # abre o inspector na porta 9229; conecte o VS Code ou o Chrome
node --inspect-brk app.js       # pausa na 1ª linha — para depurar o boot / imports
node --inspect=0.0.0.0:9229 app.js   # dentro de um container (exponha a porta; NUNCA em produção pública)

# com um runner:
node --inspect-brk ./node_modules/.bin/vitest run
NODE_OPTIONS='--inspect' npm start

7.3 Outras stacks (o conceito transfere)

StackDebugger
Pythondebugpy + extensão do VS Code; breakpoint() (dispara o pdb/o debugger configurado); python -m pdb; ipdb
Godelve (dlv debug, dlv test); integrado ao VS Code e GoLand
Java / Kotlin / C#Debugger da IDE (IntelliJ, VS Code, Rider) via JDWP / o runtime .NET — breakpoints, hot reload, evaluate
RustCodeLLDB (LLDB) no VS Code; rust-lldb/rust-gdb
ContêinerExpor a porta do inspector e attach; ou o "Dev Containers" do VS Code, que depura dentro do container
RemotoVS Code Remote-SSH: editar e depurar num servidor como se fosse local
⚠️ Inspector aberto = acesso total ao processo

A porta do inspector (9229) permite executar código arbitrário no processo. Nunca a exponha à internet nem a deixe ligada em produção. Em container de dev, mapeie só para localhost.

💼 Mercado de trabalho

Perguntas: "Diferença entre launch e attach no launch.json", "Como você depura um teste específico com breakpoints?", "O que --inspect-brk faz de diferente de --inspect?" (pausa na 1ª linha), "Como pegar um CPU profile de um processo Node em produção?" (--cpu-prof / --prof / clinic.js, sem parar), "Dá para depurar dentro de um container?" (sim — expor a porta e attach, ou Dev Containers).

✏️ Exercício 7 — Bug só no backend, sob um endpoint específico

Um endpoint POST /orders às vezes retorna 500. Os logs mostram só "TypeError: cannot read property 'total' of undefined". Descreva o setup para depurar isso com o debugger, não com console.log.

Gabarito: (1) Rodar o servidor sob o debugger: config launch no launch.json apontando para o entrypoint, com envFile, ou usar o "JavaScript Debug Terminal" e npm run dev. (2) No painel Breakpoints, marcar "Uncaught Exceptions" (e "Caught" se o erro é capturado e re-lançado) — o debugger vai parar exatamente na linha do TypeError, com o estado intacto. (3) Reproduzir: disparar o POST /orders (via Postman/cURL — Módulo 9) com um payload que causa a falha. (4) Quando pausar: olhar o Scope local — qual variável é undefined? De onde ela deveria vir (um find que não achou? um await que resolveu null? um campo ausente no body)? Subir o Call Stack para ver o valor que entrou. (5) Formular a hipótese ("quando o pedido não tem itens, cart é undefined e cart.total explode"), confirmar com outro payload, corrigir (validação/guarda) e escrever um teste com esse payload.

MÓDULO 08 · AVANÇADO

DevTools de frameworks

Objetivo: as extensões e painéis específicos que mostram o que o DevTools genérico não vê — a árvore de componentes, os hooks, o estado, os re-renders e as queries.

8.1 React DevTools

Extensão (Chrome/Firefox) que adiciona duas abas:

8.2 Vue DevTools

Extensão + o overlay standalone (@vue/devtools). Inspetor de componentes (props, data, computed, setup state — editáveis), a timeline (eventos, mutações do Pinia/Vuex, performance de componentes), inspetor de rotas (Vue Router), e o inspetor do Pinia/Vuex (estado, getters, histórico de mutações, time-travel).

8.3 Estado: Redux / Zustand / etc.

8.4 Data-fetching e roteamento

💡 Cada camada tem a sua ferramenta

Um bug de "a lista não atualiza" pode estar no DOM/CSS (Elements), na rede (Network — a request nem saiu, ou voltou vazia), no cache de dados (TanStack Query Devtools — a query está stale mas não refez), no estado (Redux DevTools — a action não disparou, ou o reducer não tratou), ou no render (React Profiler — o componente não re-renderizou porque uma prop é === à anterior). Saber qual ferramenta abrir para cada hipótese é o que torna a investigação rápida.

💼 Mercado de trabalho

Perguntas de front sénior: "Como você descobre por que um componente re-renderiza?" (React Profiler → "Why did this render?"; ou "Highlight updates"), "A tela mostra dado desatualizado — como investiga?" (TanStack Query Devtools: status da query; ou Redux DevTools: a action e o diff), "Como você inspeciona os hooks de um componente e edita o state ao vivo?" (React DevTools → Components), "O que o Redux DevTools te dá além do estado?" (histórico de actions, diff, time-travel).

✏️ Exercício 8 — Formulário lento a cada tecla

Num formulário React, digitar num campo trava por ~100 ms por caractere. Descreva a investigação com as ferramentas certas.

Gabarito: (1) React DevTools → Settings → "Highlight updates": digitar e ver o que pisca. Se a árvore inteira (ou uma seção grande) pisca a cada tecla, o problema é re-render em cascata — o state do input está num nível alto (ou num Context) que re-renderiza todos os filhos. (2) Profiler: gravar a digitação de uma letra; ver o commit; o flamegraph mostra quais componentes renderizaram; clicar nos caros → "Why did this render?" (prop nova a cada render? função inline não memoizada? o Context inteiro mudou?). (3) Confirmar no painel Performance (Módulo 5) que a long task por tecla bate com o tempo do commit. Correções típicas: mover o state do campo para o componente mais próximo (ou usar componentes não controlados / ref), fatiar o Context, memo + useCallback/useMemo nas props passadas, ou useDeferredValue/debounce para trabalho derivado pesado (validação, filtro de lista). Re-gravar para confirmar.

MÓDULO 09 · MUITO AVANÇADO

Rede, bundles e diagnóstico além do browser

Objetivo: clientes de API, interceptação de tráfego e túneis, análise de bundle, monitoramento de erro no cliente, git bisect, e depuração de mobile.

9.1 Clientes de API

FerramentaNota
PostmanO mais completo (coleções, ambientes, testes, mocks, monitors) — e o mais pesado; requer conta/nuvem para o pleno uso
InsomniaMais leve; bom suporte a GraphQL e gRPC
BrunoOpen source, local-first: as requests são arquivos de texto (.bru) que vão para o git junto do projeto — sem nuvem, versionável, revisável em PR
HoppscotchWeb, leve, open source
HTTPie (http / https)CLI com sintaxe humana: http POST api/orders name=Ana — ótimo para scripts e para colar num bug
curlUniversal; o "Copy as cURL" do Network (Módulo 4) gera exatamente a request do browser. Ver apostila de Linux & Shell
EditoresA extensão REST Client do VS Code (arquivos .http) e o cliente HTTP do JetBrains — requests versionadas ao lado do código
💡 Requests como código

Prefira ferramentas local-first (Bruno, .http) para as requests do projeto: elas entram no repositório, todo mundo tem a mesma coleção, e a revisão de PR pega mudanças de contrato. Postman/Insomnia brilham para exploração e para APIs de terceiros.

9.2 Interceptar e modificar tráfego

Quando o "Copy as cURL" e o Network não bastam — depurar um app mobile, um SDK opaco, ou modificar respostas de forma sistemática:

9.3 Túneis: expor o localhost

9.4 Análise de bundle

FerramentaUso
source-map-explorerA partir do JS + source map de produção, um treemap de "de qual arquivo/módulo vem cada byte do bundle". Independente do bundler
vite-bundle-visualizer / rollup-plugin-visualizerTreemap para projetos Vite/Rollup
webpack-bundle-analyzerO clássico para Webpack
@next/bundle-analyzerPara Next.js
Bundlephobia / pkg-size"Quanto essa dependência vai adicionar ao meu bundle?" antes de instalar
Import Cost (extensão VS Code)Mostra o tamanho de cada import ao lado da linha

O que procurar: uma dependência gorda que dá para trocar (moment → date-fns/Temporal), um pacote inteiro importado para usar uma função (import _ from 'lodash'import debounce from 'lodash-es/debounce'), duplicatas de uma lib em versões diferentes, polyfills desnecessários, e código que deveria ser lazy (ver Coverage, Módulo 6).

9.5 Monitoramento de erro no cliente

9.6 git bisect — o debugger do histórico

git bisect start
git bisect bad                 # o commit atual está quebrado
git bisect good v2.3.0         # este era bom
# o git faz checkout no meio do caminho; você testa e diz:
git bisect good   / git bisect bad
# ... repete (busca binária) até:
# "abc123 is the first bad commit"
git bisect reset

# automático, se você tem um teste/script que retorna 0=bom, !=0=ruim:
git bisect run ./repro.sh

Em ~log₂(N) passos, o git aponta o commit exato que introduziu o bug — muitas vezes o diff já mostra a causa. Requer que cada commit compile/rode (mais um motivo para commits pequenos e verdes).

9.7 Depuração mobile

💼 Mercado de trabalho

Perguntas: "Como você testa um webhook localmente?" (ngrok/cloudflared expõe o localhost), "Como inspecionar o que um app mobile envia?" (proxy — mitmproxy/Proxyman/Charles com certificado; ou remote debugging), "Como descobrir o que engordou o bundle?" (source-map-explorer / bundle analyzer; Import Cost), "Um bug apareceu essa semana e você não sabe qual mudança causou" (git bisect, idealmente git bisect run), "Como você depura o Safari do iPhone?". Ferramentas a citar: Sentry, ngrok, mitmproxy, source-map-explorer.

✏️ Exercício 9 — Escolha a ferramenta

Para cada tarefa, qual ferramenta deste módulo (ou dos anteriores)? (a) o app mobile de um cliente dá erro numa chamada de API e você não tem o código do app; (b) o webhook do Stripe não chega no seu ambiente local; (c) o bundle de produção pulou de 300 KB para 1,2 MB e você não sabe por quê; (d) "essa tela funcionava mês passado"; (e) você precisa rodar a mesma sequência de 8 requests autenticadas repetidamente para testar um fluxo.

Gabarito: (a) Um proxy (mitmproxy / Proxyman / Charles) com o certificado instalado no device — para ver a request e a resposta reais que o app faz. (b) Um túnel (ngrok / cloudflared) apontando para o localhost, e configurar essa URL pública no dashboard do Stripe; a UI do ngrok mostra as requests recebidas. (c) Um bundle analyzer / source-map-explorer no build de produção — o treemap revela a dependência nova (ou a que deixou de ser tree-shaken); comparar com o build anterior. (d) git bisect entre a última tag boa e HEAD, idealmente com git bisect run e um script que reproduz. (e) Um cliente de API com coleção (Bruno/Postman) com um ambiente que guarda o token e requests encadeadas; ou um arquivo .http versionado; ou "Copy as cURL" das 8 requests do Network num script de shell.

MÓDULO 10 · CARREIRA

Mercado de trabalho: roadmap, entrevistas e portfólio

Objetivo: converter o conteúdo dos módulos anteriores em produtividade e aprovação — onde a fluência com ferramentas pesa, roadmap, perguntas de entrevista e o que mostrar.

10.1 Onde isso conta

10.2 Roadmap de estudo (4–6 semanas)

SemanasFocoPrática
1Método de depuração + Elements & Console a fundo (Módulos 1–2)Resolver 10 "por que este elemento está assim?" só no painel; usar 8 métodos de console diferentes
2Sources: todos os tipos de breakpoint, call stack, blackboxing, overrides (Módulo 3)Depurar um bug real sem adicionar nenhum console.log; usar conditional breakpoint e logpoint; testar Local Overrides num site público
3Network + Performance + Web Vitals (Módulos 4–5)Fazer um profile de carregamento e um de interação; achar e explicar uma long task; reproduzir uma request com Copy as cURL
4Memory, Application, Lighthouse, Coverage, Rendering (Módulo 6)Caçar um leak com o fluxo three-snapshot (plantar um em um app de teste); rodar Coverage e listar o código morto
5Debugger do VS Code + Node --inspect + DevTools de framework (Módulos 7–8)Configurar um launch.json com launch/attach/test; caçar um re-render com o React Profiler
6Clientes de API, proxy, túnel, bundle analyzer, git bisect, mobile (Módulo 9); portfólioUm git bisect run; analisar o bundle de um projeto; interceptar o tráfego de um device com mitmproxy

10.3 Banco de perguntas de entrevista (com a resposta que aprova)

Júnior/pleno — "Como você depura um bug de front-end?"

Método: reproduzir de forma consistente → isolar a menor fatia que falha → formular uma hipótese falsificável → testar uma variável por vez → corrigir + teste de regressão. Ferramentas por camada: Console/Elements para DOM e CSS, Network para "a request saiu? o que voltou?", Sources com breakpoint (condicional/logpoint, não editar o arquivo) para o estado, Performance para lentidão, React/Vue DevTools para componentes e re-renders. Evito console.log às cegas — o breakpoint mostra tudo sem prever.

Pleno — "Um elemento é removido da tela e você não sabe qual código faz isso"

No painel Elements, botão direito no nó (ou no pai) → "Break on" → "node removal" (ou "subtree modifications"). Reproduzir a ação: o debugger pausa no JS que causou a mutação, com o Call Stack mostrando a cadeia até o meu código (com as libs na ignore list para reduzir ruído).

Pleno — "A página está lenta. Como você descobre o quê?"

Separar rede de execução. Network (Disable cache): há request com TTFB alto no caminho crítico? recursos grandes? waterfall em série? Performance (com CPU throttling): gravar o carregamento/interação, achar as long tasks no Main, e no Bottom-Up ordenar por Self Time para a função culpada. Não otimizo por intuição — otimizo o que o profiler aponta e re-meço.

Pleno/sénior — "Como você confirma um memory leak no browser?"

Painel Memory, fluxo de três snapshots: snapshot, executar a ação suspeita ~10× + forçar GC, snapshot, repetir, snapshot. No último, filtrar objetos alocados entre os primeiros e ordenar por Retained Size; procurar nós "Detached" (DOM desmontado ainda referenciado) e ver os Retainers (quem segura). Causas comuns: listeners/timers/subscrições sem cleanup, closures capturando objetos grandes, caches globais que só crescem.

Sénior — "Minha alteração não aparece por mais que eu recarregue"

Checar, em ordem: (1) é o arquivo/branch/ambiente certo que está rodando? (2) cache HTTP — recarregar com o DevTools aberto e "Disable cache"; (3) service worker servindo do cache — Application → Service Workers → "Update on reload" ou "Bypass for network", e Cache Storage; (4) CDN/edge cache; (5) build não rodou / HMR travou. O service worker é o suspeito nº 1 em PWA.

Sénior — "Um componente React re-renderiza demais"

React DevTools: ligar "Highlight updates" para ver o alcance; gravar no Profiler e usar "Why did this render?" em cada commit — prop nova a cada render (função/objeto inline não memoizado), Context inteiro mudando (fatiar), ou o pai renderizando (memo). Confirmar no painel Performance que o custo bate. Corrigir com memoização direcionada, split de Context, ou mover o state para mais perto — e re-medir.

Armadilha — "Eu depuro colocando console.log até achar"

Funciona, mas é o caminho lento: você adivinha onde olhar, edita, recompila, recarrega, lê — e repete. O breakpoint para no ponto e revela todo o estado sem prever; o logpoint dá o efeito do console.log sem tocar no arquivo; o conditional breakpoint pega só o caso que importa; o "pause on exceptions" para exatamente onde o erro nasce. console.log tem lugar (produção, timing, logs estruturados), mas como ferramenta principal deixa 80% do poder na mesa.

10.4 O que mostrar (portfólio)

  1. Um writeup de investigação: "diagnostiquei um vazamento de memória / uma página lenta / uma request misteriosa" — com os passos, os prints do DevTools (heap comparison, flame chart, waterfall) e o raciocínio. Vale mais que "sei usar o DevTools".
  2. Snippets de debug num gist: checagens úteis para colar no Console (contar listeners, achar elementos sem alt, medir render, dump de estado).
  3. Um launch.json completo de um projeto real (launch + attach + debug de teste + compound), documentado.
  4. Antes/depois de performance: um profile com uma long task, a correção, e o profile depois — com os números.
  5. Um git bisect run resolvido, com o script de reprodução.

10.5 Fontes para continuar

🏁 Síntese final da apostila

Quatro ideias sustentam o uso de ferramentas de debug: (1) depurar é método — reproduzir, isolar, hipótese, testar — e a ferramenta serve o método, não o contrário; (2) o breakpoint mostra tudo sem prever, enquanto o console.log só mostra o que você adivinhou imprimir; (3) cada camada tem a sua ferramenta — DOM/CSS no Elements, rede no Network, estado nos DevTools de framework, CPU/memória no Performance/Memory, histórico no git bisect — e a fluência é saber qual abrir para cada hipótese; (4) meça, não adivinhe, e re-meça para confirmar o ganho. As ferramentas evoluem a cada release; o método, não.