Node.js é um JavaScript runtime baseado no mesmo motor V8 usado no navegador Chrome do Google. Ele é frequentemente usado para construir aplicativos de servidor e terminal em várias plataformas. Node.js tem se tornado cada vez mais popular na última década porque é fácil de instalar, prático de usar, rápido, e permite que os desenvolvedores web do lado do cliente aproveitem suas habilidades em outros lugares.

Entretanto, o desenvolvimento de software continua sendo uma tarefa complexa, e seu código Node.js falhará em algum momento. Este tutorial demonstra várias ferramentas para ajudar a depurar aplicativos e encontrar a causa de um problema.

Vamos mergulhar.

Confira nosso Guia em Vídeo para Depuração de Código do Node.js

Visão geral da depuração

“Debugging” ou “depuração” é o nome dado aos vários meios de correção de defeitos do software. A correção de um bug é muitas vezes simples. Encontrar a causa do bug pode ser consideravelmente mais complexo e envolver muitas horas de reflexão.

As seções seguintes descrevem três tipos gerais de erros que você irá encontrar.

Erros de sintaxe

Seu código não segue as regras da linguagem – por exemplo, quando você omite um parêntese de fechamento ou escreve errado uma declaração como console.lag(x).

Um bom editor de código pode ajudar a detectar problemas comuns:

  • Declarações com código de cores válidas ou inválidas
  • Variáveis de verificação de tipo
  • Função de autocompletar e nomes de variáveis
  • Destaque para os parênteses correspondentes
  • Blocos de código de auto endentação
  • Detectando código inalcançável
  • Refatoração de funções desordenadas

Editores gratuitos como VS Code e Atom têm grande suporte para Node.js, JavaScript, e TypeScript (que transpõe para JavaScript). Problemas básicos de sintaxe normalmente podem ser detectados antes de você salvar e testar o seu código.

Um linter de código como o ESLint também relatará erros de sintaxe, endentação ruim, e variáveis não declaradas. O ESLint é uma ferramenta Node.js com a qual você pode instalar globalmente:

npm i eslint -g

Você pode verificar os arquivos JavaScript a partir da linha de comando usando:

eslint mycode.js

…mas é mais fácil usar um plugin de editor como ESLint para VS Code ou linter-eslint para Atom, que valida automaticamente o código à medida que você digita:

ESlint em VS Code
ESlint em VS Code.

Erros lógicos

Seu código funciona, mas não funciona como você espera. Por exemplo, um usuário não é desconectado quando o solicita; um relatório mostra números incorretos; os dados não são totalmente salvos em um banco de dados; etc.

Erros de lógica podem ser causados por:

  • Usando a variável errada
  • Condições incorretas, por exemplo, if (a > 5) em vez de if (a < 5)
  • Cálculos que não levam em conta a precedência do operador, por exemplo, 1+2*3 resulta em 7 ao invés de 9.

Erros Runtime (ou execução)

Um erro só se torna evidente quando o aplicativo é executada, o que muitas vezes leva a uma falha. Os erros de tempo de execução podem ser causados por:

  • Dividindo por uma variável que foi definida como zero
  • Tentativa de acessar um item de matriz que não existe
  • Tentando escrever em um arquivo somente leitura

Erros lógicos e de tempo de execução são mais difíceis de detectar, embora as seguintes técnicas de desenvolvimento possam ajudar:

  1. Use o Desenvolvimento Guiado por Testes: TTD incentiva você a escrever testes antes que uma função seja desenvolvida, por exemplo, X é retornado da funçãoY quando Z é passado como um parâmetro. Estes testes são executados durante o desenvolvimento inicial e atualizações subsequentes para garantir que o código continue a funcionar como esperado.
  2. Use um sistema de rastreamento de problemas: Não há nada pior do que um e-mail afirmando “Seu software não funciona”! Sistemas de rastreamento de problemas permitem que você registre problemas específicos, etapas de reprodução de documentos, determine prioridades, atribua desenvolvedores e acompanhe o progresso das correções.
  3. Use o controle de origem: Um sistema de controle de código fonte como o Git irá ajudá-lo a fazer backup do código, gerenciar as revisões e identificar onde um bug foi introduzido. Os repositórios online, incluindo Github e Bitbucket, fornecem espaço livre e ferramentas para projetos menores ou de código aberto.

Você ainda encontrará bugs do Node.js, mas as seções seguintes descrevem maneiras de localizar esse erro elusivo.

Definir Variáveis de Ambiente Apropriadas do Node.js

As variáveis de ambiente definidas no sistema operacional do host podem controlar as configurações do o aplicativo Node.js e do módulo. A mais comum é NODE_ENV, que normalmente é configurada para desenvolvimento quando da depuração ou produção quando rodando em um servidor ao vivo. Configure ambientes variáveis no MacOS ou Linux com o comando:

NODE_ENV=development

ou no prompt de comando (clássico) do Windows:

set NODE_ENV=development

ou Windows Powershell:

$env:NODE_ENV="development"

No popular Express.js framework, configurar NODE_ENV para desenvolvimento desabilita o cache de arquivos de modelo e emite mensagens de erro verboso, o que pode ser útil na depuração. Outros módulos podem oferecer características similares e você pode adicionar uma condição NODE_ENV aos aplicativos, por exemplo

// running in development mode?
const devMode = (process.env.NODE_ENV !== 'production');

if (devMode) {
  console.log('application is running in development mode');
}

Você também pode usar o método Node’s util.debuglog para emitir condicionalmente mensagens de erro, por exemplo

import { debuglog } from 'util';
const myappDebug = debuglog('myapp');
myappDebug('log something');

Este aplicativo só emitirá a mensagem de log quando NODE_DEBUG estiver configurado para myapp ou um wildcard como * ou my*.

Use as opções de linha de comando do Node.js

Os scripts de nó são normalmente lançados com o nó seguido pelo nome do script de entrada:

node app.js

Você também pode definir opções de linha de comando para controlar vários aspectos do tempo de execução. As bandeiras úteis para depuração incluem:

  • --check
    sintaxe verifique o script sem executar
  • --trace-warnings
    produzir um rastreamento de pilha quando as promessas JavaScript não resolvem ou rejeitam
  • --enable-source-maps
    mostrar mapas de origem ao usar um transpiler como o TypeScript
  • --throw-deprecation
    avisar quando as características do Node.js depreciado são usadas
  • --redirect-warnings=file
    emitir avisos para um arquivo em vez de stderr
  • --trace-exit
    emitem um rastreamento de pilha quando process.exit() é chamado.

Mensagens de saída para o console

A saída de uma mensagem de console é uma das maneiras mais simples de depurar um aplicativo Node.js:

console.log(`someVariable: ${ someVariable }`);

Poucos desenvolvedores percebem que existem muitos outros métodos de console:

Método Console Descrição
.log(msg) mensagem de console padrão
.log('%j', obj) objeto de saída como uma string JSON compacta
.dir(obj, opt) propriedades dos objetos de impressão bonita
.table(obj) matrizes de saída e objetos em formato tabular
.error(msg) uma mensagem de erro
.count(label) incrementar um contador nomeado e a saída
.countReset(label) zerar um contador nomeado
.group(label) indentar um grupo de mensagens
.groupEnd(label) terminar um grupo
.time(label) inicia um temporizador chamado
.timeLog(label) relata o tempo transcorrido
.timeEnd(label) pára um temporizador nomeado
.trace() emitir um rastreamento de pilha (uma lista de todas as chamadas de função feitas)
.clear() desobstruir o console

console.log() também aceita uma lista de valores separados por vírgula:

let x = 123;
console.log('x:', x);
// x: 123

…embora a desestruturação do ES6 ofereça resultados similares com menos esforço:

console.log({ x });
// { x: 123 }

O console.dir() comanda as propriedades do objeto pretty-prints da mesma forma que o util.inspect():

console.dir(myObject, { depth: null, color: true });

Controvérsia do Console

Alguns desenvolvedores afirmam que você nunca deve usar console.log() porque:

  • Você está mudando de código e pode alterar algo ou esquecer de removê-lo, e
  • Não há necessidade quando há melhores opções de depuração.

Não acredite em ninguém que afirma nunca usar console.log()! O logging é rápido e sujo, mas todos o usam em algum momento. Use qualquer ferramenta ou técnica que você preferir. Consertar um bug é mais importante do que o método que você adota para encontrá-lo.

Use um Sistema de Registro de Terceiros

Sistemas de registro de terceiros fornecem recursos mais sofisticados como níveis de mensagens, verbosidade, classificação, saída de arquivos, criação de perfis, relatórios e muito mais. Soluções populares incluem cabine, nível de log, morgan, pino, signale, storyboard, traçador e winston.

Use o Inspetor V8

O motor JavaScript V8 fornece um cliente de depuração que você pode usar no Node.js. Comece um aplicativo usando a inspeção do Node, por exemplo

node inspect app.js

O depurador para na primeira linha e exibe um prompt de debug> debug:

$ node inspect .\mycode.js
< Debugger listening on ws://127.0.0.1:9229/143e23fb
< For help, see: https://nodejs.org/en/docs/inspector
<
 ok
< Debugger attached.
<
Break on start in mycode.js:1
> 1 const count = 10;
  2
  3 for (i = 0; i < counter; i++) {
debug>

Entre na ajuda para ver uma lista de comandos. Você pode passar através da aplicativo entrando:

  • cont ou c: continuar a execução
  • next ou n: execute o próximo comando
  • step ou s: entrar em uma função que está sendo chamada
  • out ou o: sair de uma função e retornar à declaração de chamada
  • pause: pausa do código de execução
  • watch(‘myvar’): veja uma variável
  • setBreakPoint() ou sb(): definir um ponto de quebra
  • restart: reinicie o script
  • .exit ou Ctrl | Cmd + D: sair do depurador

É verdade que esta opção de depuração é demorada e complicada. Use-a apenas quando não houver outra opção, como quando você estiver executando código em um servidor remoto e não puder se conectar de outro lugar ou instalar software adicional.

Use o navegador Chrome para depurar o código no Node.js

A opção de inspeção Node.js usada acima inicia um servidor Web Socket que escuta na porta 9229 do localhost. Ele também inicia um cliente de depuração baseado em texto, mas é possível usar clientes gráficos – como o integrado no Google Chrome e navegadores baseados no Chrome como Chromium, Edge, Opera, Vivaldi e Brave.

Para depurar um aplicativo web típico, inicie-a com a opção –inspect para habilitar o servidor Web Socket do depurador V8:

node --inspect index.js

Nota:

  • index.js é presumido ser o script de entrada da aplicativo.
  • Certifique-se de usar --inspect com traços duplos para garantir que você não inicie o cliente de depuração baseado em texto.
  • Você pode usar nodemon ao invés de node se você quiser reiniciar automaticamente a aplicativo quando um arquivo for alterado.

Por padrão, o depurador só aceitará conexões de entrada da máquina local. Se você estiver executando o aplicativo em outro dispositivo, máquina virtual, ou container Docker, use:

node --inspect=0.0.0.0:9229 index.js
opção de node inspect
opção de node inspect.

Você também pode usar --inspect-brk ao invés de --inspect para interromper o processamento (definir um ponto de parada) na primeira linha para que você possa passar pelo código desde o início.

Abra um navegador baseado no Chrome e entre chrome://inspect na barra de endereços para visualizar dispositivos locais e em rede:

Ferramenta de inspeção do Chrome
Ferramenta de inspeção do Chrome

Se o seu plicativo Node.js também não aparecer como um alvo remoto:

  • Clique em Open dedicated DevTools for Node e escolha o endereço e a porta, ou
  • Verifique Discover network targets, clique em Configure, depois adicione o endereço IP e a porta do dispositivo onde ele está rodando.

Clique no link de inspect do Target para abrir o cliente DevTools debugger. Isto deve ser familiar a qualquer um que tenha usado DevTools para depuração de código do lado do cliente:

Chrome DevTools
Chrome DevTools.

Mude para o painel Sources. Você pode abrir qualquer arquivo pressionando Cmd | Ctrl + P e digitando seu nome de arquivo (como index.js).

Entretanto, é mais fácil adicionar a pasta do seu projeto ao espaço de trabalho. Isso permite carregar, editar e salvar arquivos diretamente do DevTools (se você acha que isso é uma boa idéia é outra questão!)

  1. Clique em + Add folder to workspace
  2. Selecione a localização do seu projeto Node.js
  3. Pressione Agree para permitir mudanças no arquivo

Agora você pode carregar arquivos a partir da árvore de diretórios à esquerda:

Chrome DevTools Sources panel
Chrome DevTools Sources Panel

Clique em qualquer número de linha para definir um ponto de parada assinalado por um marcador azul.

A depuração é baseada em breakpoints. Estes especificam onde o depurador deve interromper a execução do programa e mostrar o estado atual do programa (variáveis, Call Stack, etc.)

Você pode definir qualquer número de breakpoints na interface do usuário. Outra opção é colocar um depurador; declaração em seu código, que quando um depurador é anexado.

Carregue e use o seu aplicativo web para abrir a declaração onde um ponto de parada é definido. No exemplo aqui, http://localhost:3000/ é aberto em qualquer navegador, e o DevTools irá interromper a execução na linha 44:

Chrome breakpoint
Chrome breakpoint

O painel do lado direito mostra:

  • Uma linha de ícones de ação (veja abaixo).
  • Um painel de Watch permite que você monitore as variáveis clicando no ícone + e digitando seus nomes.
  • Um painel de Breakpoints mostra uma lista de todos os breakpoints e permite que eles sejam habilitados ou desabilitados.
  • Um painel de Scope mostra o estado de todas as variáveis locais, modulares e globais. Você inspecionará este painel com mais frequência.
  • Um painel de Call Stack mostra a hierarquia de funções chamadas para chegar a este ponto.

Uma linha de ícones de ação é mostrada acima Paused on breakpoint:

Ícones do Chrome breakpoint
Ícones do Chrome breakpoint

Da esquerda para a direita, estes executam as seguintes ações:

  • resume execution: Continuar o processamento até o próximo ponto de parada
  • step over: Execute o próximo comando, mas fique dentro do bloco de código atual – não pule para nenhuma função que ele chama
  • step into: Executar o próximo comando e pular para qualquer função conforme necessário
  • step into: Continuar o processamento até o final da função e retornar ao comando de chamada
  • step: Semelhante ao step into, exceto que não pulará para funções assíncronas
  • deactivate todos os breakpoints
  • pause on exceptions: Interrompa o processamento quando ocorrer um erro.

Condicional breakpoints

Às vezes é necessário exercer um pouco mais de controle sobre os breakpoints. Imagine que você tem um loop que completou 1.000 iterações, mas você só está interessado no estado da última:


for (let i = 0; i < 1000; i++) {
  // set breakpoint here
}

Ao invés de clicar 999 vezes em resume execution, você pode clicar com o botão direito do mouse na linha, escolher Add conditional breakpoint, e insera uma condição como i = 999:

Condicional breakpoint do Chrome
Condicional breakpoint do Chrome

O Chrome mostra breakpoints condicionados em amarelo ao invés de azul. Neste caso, o ponto de parada só é acionado na última iteração do laço.

Pontos de Log

Os pontos de log implementam efetivamente o console.log() sem nenhum código! Uma expressão pode ser gerada quando o código executa qualquer linha, mas não para o processamento, ao contrário de um ponto de parada.

Para adicionar um log point, clique com o botão direito do mouse em qualquer linha, escolha Add log point, e digite uma expressão, por exemplo 'loop counter i', i:

Ponto de registro Chrome
Ponto de registro Chrome

O console DevTools sai loop counter i: 0 para loop counter i: 999 no exemplo acima.

Use o VS Code para depurar aplicativos do Node.js

VS Code, ou Visual Studio Code, é um editor de código gratuito da Microsoft que se tornou popular entre os desenvolvedores web. O aplicativo está disponível para Windows, macOS e Linux e é desenvolvido usando tecnologias web no framework Electron.

O VS Code suporta Node.js e tem um cliente de depuração embutido. A maioria dos aplicativos pode ser depurada sem nenhuma configuração; o editor iniciará automaticamente o servidor e o cliente de depuração.

Abra o arquivo inicial (como index.js), ative o painel Run e Debug, clique no botão Run e Debug, e escolha o ambiente Node.js. Clique em qualquer linha para ativar um ponto de parada mostrado como um ícone de círculo vermelho. Então, abra o aplicativo em um navegador como antes – o código VS interrompe a execução quando o ponto de parada é atingido:

VS Code breakpoint
VS Code breakpoint

As VariablesWatchCall Stack, e Breakpoints são similares às mostradas nas ferramentas do Chrome DevTools. O painel Loaded Scripts mostra quais scripts foram carregados, embora muitos sejam internos ao Node.js.

A barra de ferramentas de ícones de ação permite que você o faça:

  • resume execution: Continuar o processamento até o próximo ponto de parada
  • step over: Execute o próximo comando, mas fique dentro da função atual – não pule para nenhuma função que ele chama
  • step into: Executar o próximo comando e pular para qualquer função que ele chame
  • step out: Continuar o processamento até o final da função e retornar ao comando de chamada
  • restart: Reinicie o aplicativo e o depurador
  • stop: Parar o aplicativo e o depurador

Como o Chrome DevTools, você pode clicar com o botão direito do mouse em qualquer linha para adicionar Conditional breakpoints e Log points.

Para mais informações, consulte Depuração em Visual Studio Code.

Configuração avançada de depuração do VS Code

Outra configuração de código VS pode ser necessária se você quiser depurar o código em outro dispositivo, uma máquina virtual, ou precisar usar opções alternativas de lançamento, como nodemon.

O VS Code armazena configurações de depuração em um arquivo launch.json dentro de um diretório .vscode em seu projeto. Abra o painel Run e Debug, clique em arquivo create a launch.json e escolha o ambiente Node.js para gerar este arquivo. Um exemplo de configuração é fornecido:

Configuração do depurador do VS Code.
Configuração do depurador do VS Code.

Qualquer número de configurações pode ser definido como objetos na matriz "configurations". Clique em Add Configuration… e selecione uma opção apropriada.

Uma configuração individual do Node.js pode ser qualquer uma das duas:

  1. Iniciar um processo em si, ou
  2. Anexar a um servidor de depuração Web Socket, talvez rodando em uma máquina remota ou em um contêiner Docker.

Por exemplo, para definir uma configuração nodemon, selecione Node.js: Nodemon Setup e mude o script de entrada “program” se necessário:

{
  // custom configuration
  "version": "0.2.0",
  "configurations": [
    {
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "name": "nodemon",
      "program": "${workspaceFolder}/index.js",
      "request": "launch",
      "restart": true,
      "runtimeExecutable": "nodemon",
      "skipFiles": [
        "<node_internals>/**"
      ],
      "type": "pwa-node"
    }
  ]
}

Salve o arquivo launch.json e o nodemon (o “nome” da configuração) aparece na lista suspensa na parte superior do painel Run and Debug. Clique no ícone verde de execução para começar a usar essa configuração e execute o aplicativo usando nodemon:

Depuração do VS Code com nodemon
Depuração do VS Code com nodemon

Como antes, você pode adicionar breakpoints, condicional breakpoints e pontos de registro. A principal diferença é que o nodemon irá automaticamente reiniciar seu servidor quando um arquivo for modificado.

Para maiores informações, consulte as configurações de lançamento do código VS.

As seguintes extensões do VS Code também podem ajudá-lo a depurar o código hospedado em ambientes de servidores remotos ou isolados:

Outras opções de depuração do Node.js

O Node.js Debugging Guide fornece conselhos para uma gama de editores de texto e IDEs, incluindo Visual Studio, JetBrains WebStorm, Gitpod e Eclipse. Atom oferece uma extensão node-debug, que integra o depurador do Chrome DevTools no editor.

Uma vez que o seu aplicativo esteja ativo, você pode considerar o uso de serviços de depuração comercial como LogRocket e Sentry.io, que podem gravar e reproduzir erros do cliente e servidor encontrados por usuários reais.

Resumo

Historicamente, a depuração JavaScript tem sido difícil, mas tem havido enormes melhorias na última década. A escolha é tão boa – se não melhor – quanto as fornecidas para outras linguagens.

Use qualquer ferramenta que seja prática para localizar um problema. Não há nada de errado com console.log() para uma rápida busca de bugs, mas o Chrome DevTools ou VS Code pode ser preferível para problemas mais complexos. As ferramentas podem ajudá-lo a criar um código mais robusto e você gastará menos tempo corrigindo bugs.

Com que prática de depuração do Node.js você usa? Compartilhe na seção de comentários abaixo!

Craig Buckler

Freelance UK web developer, writer, and speaker. Has been around a long time and rants about standards and performance.