Node.js es un JavaScript runtime basado en el mismo motor V8 utilizado en el navegador Chrome de Google. Se suele utilizar para crear aplicaciones multiplataforma del lado del servidor y del terminal. Node.js se ha hecho cada vez más popular en la última década porque es fácil de instalar, práctico de usar, rápido y permite a los desarrolladores web del lado del cliente aprovechar sus habilidades en otro lugar.

Sin embargo, el desarrollo de software sigue siendo una tarea compleja, y tu código Node.js fallará en algún momento. Este tutorial muestra varias herramientas para ayudar a depurar las aplicaciones y encontrar la causa de un problema.

Entremos de lleno.

Consulta Nuestro VideoTutorial para Depurar el Código de Node.js

Visión general de la depuración

«Depuración» es el nombre que se da a las distintas herramientas para arreglar los defectos del software. Arreglar un fallo suele ser sencillo. Encontrar la causa del fallo puede ser bastante más complejo y requerir muchas horas de trabajo duro.

En los siguientes apartados se describen tres tipos generales de errores con los que te encontrarás.

Errores de sintaxis

Tu código no sigue las reglas del lenguaje – por ejemplo, cuando omites un corchete de cierre o escribes mal una sentencia como console.lag(x).

Un buen editor de código puede ayudar a detectar los problemas más comunes:

  • Codificación por colores de las declaraciones válidas o no válidas
  • Comprobación de tipo de las variables
  • Autocompletar nombres de funciones y variables
  • Resaltar paréntesis coincidentes
  • Autoindentación de bloques de código
  • Detección de código no accesible
  • Refactorización de funciones desordenadas

Los editores gratuitos como VS Code y Atom tienen un gran soporte para Node.js, JavaScript y TypeScript (que se transpila a JavaScript). Los problemas básicos de sintaxis suelen detectarse antes de guardar y probar el código.

Un linter de código como ESLint también informará de los errores de sintaxis, de la mala indentación y de las variables no declaradas. ESLint es una herramienta de Node.js que puedes instalar globalmente:

npm i eslint -g

Puedes comprobar los archivos JavaScript desde la línea de comandos utilizando:

eslint mycode.js

…pero es más fácil utilizar un plugin del editor como ESLint para VS Code o linter-eslint para Atom, que validan automáticamente el código mientras escribes:

ESlint in VS Code
ESlint en VS Code.

Errores lógicos

Tu código se ejecuta pero no funciona como esperas. Por ejemplo, un usuario no cierra la sesión cuando lo solicita; un informe muestra cifras incorrectas; los datos no se guardan completamente en una base de datos; etc.

Los errores lógicos pueden ser causados por:

  • Uso de una variable incorrecta
  • Condiciones incorrectas, por ejemplo, if (a > 5) en lugar de if (a < 5)
  • Cálculos que no tienen en cuenta la precedencia de los operadores, por ejemplo, 1+2*3 da como resultado 7 en lugar de 9.

Errores de tiempo de ejecución (o errores runtime)

Un error sólo se hace evidente cuando se ejecuta la aplicación, lo que suele provocar un fallo. Los errores de ejecución pueden ser causados por:

  • Dividir por una variable que se ha puesto a cero
  • Intentar acceder a un elemento de la matriz que no existe
  • Intentar escribir en un archivo de sólo lectura

Los errores lógicos y de ejecución son más difíciles de detectar, aunque las siguientes técnicas de desarrollo pueden ayudar:

  1. Utiliza el Desarrollo Orientado a Pruebas: TTD te anima a escribir pruebas antes de que se desarrolle una función, por ejemplo, X se devuelve de la funciónY cuando se pasa Z como parámetro. Estas pruebas se ejecutan durante el desarrollo inicial y las actualizaciones posteriores para garantizar que el código sigue funcionando como se espera.
  2. Utiliza un sistema de seguimiento de incidencias: No hay nada peor que un correo electrónico en el que se diga «Tu software no funciona» Los sistemas de seguimiento de incidencias te permiten registrar problemas específicos, documentar los pasos de reproducción, determinar prioridades, asignar desarrolladores y seguir el progreso de las correcciones.
  3. Utiliza el control del código fuente: Un sistema de control de fuentes como Git te ayudará a hacer copias de seguridad del código, gestionar las revisiones e identificar dónde se ha introducido un error. Los repositorios online, como Github y Bitbucket, ofrecen espacio y herramientas gratuitas para proyectos más pequeños o de código abierto.

Seguirás encontrando errores de Node.js, pero las siguientes secciones describen las formas de localizar ese escurridizo error.

Establece las variables de entorno de Node.js adecuadas

Las variables de entorno establecidas en el sistema operativo del host pueden controlar la configuración de la aplicación y los módulos de Node.js. La más común es NODE_ENV, que normalmente se establece en desarrollo cuando se depura o en producción cuando se ejecuta en un servidor en vivo. Establece las variables de entorno en macOS o Linux con el comando:

NODE_ENV=development

o en el símbolo del sistema (clásico) de Windows:

set NODE_ENV=development

o en Windows Powershell:

$env:NODE_ENV="development"

En el popular framework Express.js, al establecer NODE_ENV como desarrollo se desactiva el almacenamiento en caché de los archivos de plantilla y se emiten mensajes de error detallados, lo que puede ser útil para la depuración. Otros módulos pueden ofrecer características similares, y puedes añadir una condición NODE_ENV a tus aplicaciones, por ejemplo

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

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

También puedes utilizar el método util.debuglog de Node para emitir mensajes de error de forma condicional, por ejemplo

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

Esta aplicación sólo emitirá el mensaje de registro cuando NODE_DEBUG se establezca como myapp o un comodín como * o my*.

Utiliza las opciones de la línea de comandos de Node.js

Los scripts de Node suelen lanzarse con node seguido del nombre del script de entrada:

node app.js

También puedes establecer opciones de línea de comandos para controlar varios aspectos del tiempo de ejecución. Las banderas útiles para la depuración incluyen:

  • --check
    comprueba la sintaxis del script sin ejecutar
  • --trace-warnings
    mostrar un seguimiento de la pila cuando JavaScript Promises no se resuelven o se rechazan
  • --enable-source-maps
    mostrar los mapas de origen cuando se utiliza un transpilador como TypeScript
  • --throw-deprecation
    avisar cuando se utilicen funciones obsoletas de Node.js
  • --redirect-warnings=file
    enviar las advertencias a un archivo en lugar de a stderr
  • --trace-exit
    mostrar un seguimiento de la pila cuando se llama a process.exit().

Salida de mensajes en la consola

Dar salida a un mensaje en la consola es una de las formas más sencillas de depurar una aplicación Node.js:

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

Pocos desarrolladores se dan cuenta de que hay muchos otros métodos de consola:

Método de la consola Descripción
.log(msg) mensaje de consola estándar
.log('%j', obj) salida del objeto como una cadena JSON compacta
.dir(obj, opt) imprimir las propiedades de los objetos en formato pretty-print
.table(obj) salida de arrays y objetos en formato tabular
.error(msg) un mensaje de error
.count(label) incrementar un contador con nombre y salida
.countReset(label) restablecer un contador con nombre
.group(label) sangrar un grupo de mensajes
.groupEnd(label) termina un grupo
.time(label) inicia un temporizador con nombre
.timeLog(label) informa del tiempo transcurrido
.timeEnd(label) detiene un temporizador con nombre
.trace() muestra un seguimiento de la pila (una lista de todas las llamadas a funciones realizadas)
.clear() borra la consola

console.log() también acepta una lista de valores separados por comas:

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

…aunque la desestructuración de ES6 ofrece un resultado similar con menos esfuerzo:

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

El comando console.dir( ) imprime las propiedades de los objetos del mismo modo que util.inspect():

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

Controversia sobre la consola

Algunos desarrolladores afirman que nunca debes utilizar console.log() porque:

  • Estás cambiando el código y puedes alterar algo u olvidar eliminarlo, y
  • No es necesario cuando hay mejores opciones de depuración.

¡No creas a nadie que diga que nunca usa console.log()! El registro es rápido y sucio, pero todo el mundo lo utiliza en algún momento. Utiliza la herramienta o técnica que prefieras. Solucionar un fallo es más importante que el método que adoptes para encontrarlo.

Utiliza un sistema de registro de terceros

Los sistemas de registro de terceros proporcionan funciones más sofisticadas, como niveles de mensajería, verbosidad, clasificación, salida de archivos, elaboración de perfiles, informes y mucho más. Las soluciones más populares son cabin, loglevel, morgan, pino, signale, storyboard, tracer y winston.

Utiliza el Inspector V8

El motor V8 de JavaScript proporciona un cliente de depuración que puedes utilizar en Node.js. Inicia una aplicación utilizando node inspect, por ejemplo

node inspect app.js

El depurador se detiene en la primera línea y muestra un aviso de depuración>:

$ 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>

Utiliza la ayuda para ver una lista de comandos. Puedes avanzar por la aplicación introduciendo:

  • cont o c: continuar la ejecución
  • next o n: ejecutar el siguiente comando
  • step o s: entrar en una función a la que se llama
  • out o o: salir de una función y volver a la sentencia que la llama
  • pause: pausa la ejecución del código
  • watch(‘myvar’): vigilar una variable
  • setBreakPoint() o sb(): establece un punto de interrupción
  • restart: reiniciar el script
  • .exit o Ctrl | Cmd + D: salir del depurador

Hay que reconocer que esta opción de depuración requiere mucho tiempo y es poco manejable. Utilízala sólo cuando no haya otra opción, como cuando estés ejecutando código en un servidor remoto y no puedas conectarte desde otro lugar o instalar software adicional.

Utiliza el navegador Chrome para depurar el código Node.js

La opción de inspección de Node.js utilizada anteriormente inicia un servidor Web Socket que mira al puerto localhost 9229. También inicia un cliente de depuración basado en texto, pero es posible utilizar clientes gráficos, como el integrado en Google Chrome y en navegadores basados en Chrome como Chromium, Edge, Opera, Vivaldi y Brave.

Para depurar una aplicación web típica, iníciala con la opción –inspect para activar el servidor Web Socket del depurador V8:

node --inspect index.js

Nota:

  • se supone que index.js es el script de entrada de la aplicación.
  • Asegúrate de utilizar --inspect con doble guión para garantizar que no inicias el cliente del depurador basado en texto.
  • Puedes utilizar nodemon en lugar de node si quieres reiniciar automáticamente la aplicación cuando se modifique un archivo.

Por defecto, el depurador sólo acepta conexiones entrantes desde la máquina local. Si estás ejecutando la aplicación en otro dispositivo, máquina virtual o contenedor Docker, utiliza:

node --inspect=0.0.0.0:9229 index.js
node inspect
opción de inspección del nodo.

También puedes utilizar --inspect-brk en lugar de --inspect para detener el procesamiento (establecer un punto de interrupción) en la primera línea y así poder recorrer el código desde el principio.

Abre un navegador basado en Chrome e introduce chrome://inspect en la barra de direcciones para ver los dispositivos locales y en red:

Chrome inspect tool
Herramienta de inspección de Chrome.

Si tu aplicación Node.js no aparece como Objetivo Remoto, tampoco:

  • Haz clic en Abrir DevTools dedicado para Node y elige la dirección y el puerto, o
  • Marca la opción Discover network targets, haz clic en Configure, y luego añade la dirección IP y el puerto del dispositivo donde se está ejecutando.

Haz clic en el enlace de Inspect del objetivo para lanzar el cliente de depuración DevTools. Esto debería ser familiar para cualquiera que haya utilizado DevTools para la depuración de código del lado del cliente:

Chrome DevTools
Chrome DevTools.

Cambia al panel de Sources. Puedes abrir cualquier archivo pulsando Cmd | Ctrl + P e introduciendo su nombre (como index.js).

Sin embargo, es más fácil añadir la carpeta de tu proyecto al espacio de trabajo. Esto te permite cargar, editar y guardar archivos directamente desde DevTools (si crees que es una buena idea es otra cuestión)

  1. Haz clic en + Añadir carpeta al espacio de trabajo
  2. Selecciona la ubicación de tu proyecto Node.js
  3. Pulsa Aceptar para permitir los cambios en los archivos

Ahora puedes cargar archivos desde el árbol de directorios de la izquierda:

Chrome DevTools Sources panel
Panel de Sources de DevTools de Chrome.

Haz clic en cualquier número de línea para establecer un punto de interrupción indicado por un marcador azul.

La depuración se basa en los puntos de interrupción. Éstos especifican dónde el depurador debe detener la ejecución del programa y mostrar el estado actual del mismo (variables, pila de llamadas, etc.)

Puedes definir cualquier número de puntos de interrupción en la interfaz de usuario. Otra opción es colocar una sentencia debugger; en tu código, que se detiene cuando se conecta un depurador.

Carga y utiliza tu aplicación web para llegar a la sentencia en la que se ha establecido un punto de interrupción. En este ejemplo, http://localhost:3000/ se abre en cualquier navegador, y DevTools detendrá la ejecución en la línea 44:

Chrome breakpoint
Punto de interrupción de Chrome.

El panel de la derecha muestra:

  • Una fila de iconos de acción (ver abajo).
  • Un panel de Watch te permite controlar las variables haciendo clic en el icono + e introduciendo sus nombres.
  • Un panel Breakpoints muestra una lista de todos los puntos de ruptura y permite activarlos o desactivarlos.
  • El panel Scope muestra el estado de todas las variables locales, de módulo y globales. Este panel es el que inspeccionarás más a menudo.
  • Un panel de Call Stack muestra la jerarquía de funciones llamadas para llegar a este punto.

Una fila de iconos de acción se muestra por encima de Paused on breakpoint:

Chrome breakpoint icons
Iconos de puntos de interrupción de Chrome.

De izquierda a derecha, realizan las siguientes acciones:

  • resume execution: Continuar el proceso hasta el siguiente punto de interrupción
  • step over: Ejecuta el siguiente comando pero mantente dentro del bloque de código actual – no saltes a ninguna función a la que llame
  • step into: Ejecuta el siguiente comando y salta a cualquier función si es necesario
  • step out: Continúa el proceso hasta el final de la función y vuelve al comando que la llama
  • step: Similar a step into, excepto que no saltará a las funciones asíncronas
  • deactivate todos los puntos de interrupción
  • pause on exceptions: Detener el procesamiento cuando se produce un error

Puntos de interrupción condicionales

A veces es necesario ejercer un poco más de control sobre los puntos de interrupción. Imagina que tienes un bucle que ha completado 1.000 iteraciones, pero sólo te interesa el estado de la última:


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

En lugar de hacer clic en reanudar la ejecución 999 veces, puedes hacer clic con el botón derecho en la línea, elegir Add conditional breakpoint e introducir una condición como i = 999:

Chrome conditional breakpoint
Punto de interrupción condicional del cromo.

Chrome muestra los puntos de interrupción condicionales en amarillo en lugar de azul. En este caso, el punto de interrupción sólo se activa en la última iteración del bucle.

Puntos de registro

Los puntos de registro implementan efectivamente console.log() sin ningún código Una expresión puede salir cuando el código ejecuta cualquier línea, pero no detiene el proceso, a diferencia de un punto de interrupción.

Para añadir un punto de registro, haz clic con el botón derecho del ratón en cualquier línea, elige Añadir log point e introduce una expresión, por ejemplo 'loop counter i', i:

Chrome logpoint
Punto de registro de Chrome.

En el ejemplo anterior, la consola de DevTools muestra loop counter i: 0 a loop counter i: 999.

Usa VS Code para depurar aplicaciones Node.js

VS Code, o Visual Studio Code, es un editor de código gratuito de Microsoft que se ha hecho popular entre los desarrolladores web. La aplicación está disponible para Windows, macOS y Linux, y está desarrollada con tecnologías web en el marco de Electron.

VS Code es compatible con Node.js y tiene un cliente de depuración integrado. La mayoría de las aplicaciones pueden ser depuradas sin ninguna configuración; el editor iniciará automáticamente el servidor y el cliente de depuración.

Abre el archivo inicial (como index.js), activa el panel Run and Debug, haz clic en el botón Run and Debug y elige el entorno Node.js. Haz clic en cualquier línea para activar un punto de interrupción que se muestra como un icono de círculo rojo. A continuación, abre la aplicación en un navegador como antes – VS Code detiene la ejecución cuando se alcanza el punto de interrupción:

VS Code breakpoint
Punto de ruptura de VS Code.

Los paneles Variables, Watch, Call Stack y Breakpoints son similares a los que se muestran en Chrome DevTools. El panel Loaded Scripts muestra los scripts que se han cargado, aunque muchos son internos de Node.js.

La barra de herramientas de iconos de acción te permite

  • resume execution: Continúa el procesamiento hasta el siguiente punto de interrupción
  • step over: Ejecuta el siguiente comando pero permanece dentro de la función actual – no saltes a ninguna función a la que llame
  • step into: Ejecuta el siguiente comando y salta a cualquier función a la que llame
  • step out: Continuar el proceso hasta el final de la función y volver al comando que llama
  • restart la aplicación y el depurador
  • stop la aplicación y el depurador

Al igual que las DevTools de Chrome, puedes hacer clic con el botón derecho en cualquier línea para añadir puntos de Conditional breakpoints y Log points.

Para más información, consulta Depuración en Visual Studio Code.

Configuración de depuración avanzada de VS Code

Puede ser necesaria una configuración adicional de VS Code si quieres depurar el código en otro dispositivo, en una máquina virtual, o si necesitas utilizar opciones de lanzamiento alternativas como nodemon.

VS Code almacena las configuraciones de depuración en un archivo launch.json dentro de un directorio .vscode en tu proyecto. Abre el panel Run and Debug, haz clic en create a launch.json file y elige el entorno Node.js para generar este archivo. Se proporciona un ejemplo de configuración:

VS Code debugger configuration
Configuración del depurador de VS Code.

Se puede definir cualquier número de ajustes de configuración como objetos en la matriz "configurations". Haz clic en Add Configuration… y selecciona una opción adecuada.

Una configuración individual de Node.js puede

  1. Lanzar un proceso por sí mismo, o
  2. Adjuntar a un servidor de depuración Web Socket, quizás ejecutado en una máquina remota o en un contenedor Docker.

Por ejemplo, para definir una configuración de nodemon, selecciona Node.js: Nodemon Setup y cambia el script de entrada del «programa» si es necesario:

{
  // 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"
    }
  ]
}

Guarda el archivo launch.json y nodemon (el «nombre» de la configuración) aparecerá en la lista desplegable de la parte superior del panel de Run and Debug. Haz clic en el icono verde de ejecución para empezar a utilizar esa configuración y lanzar la aplicación utilizando nodemon:

VS Code debugging with nodemon
Depuración de VS Code con nodemon.

Como antes, puedes añadir puntos de ruptura, puntos de ruptura condicionales y puntos de registro. La principal diferencia es que nodemon reiniciará automáticamente tu servidor cuando se modifique un archivo.

Para más información, consulta las configuraciones de lanzamiento de VS Code.

Las siguientes extensiones de VS Code también pueden ayudarte a depurar código alojado en entornos de servidores remotos o aislados:

  • Remote – Containers: Conéctate a aplicaciones que se ejecutan en contenedores Docker
  • Remote – SSH: Conéctate a aplicaciones que se ejecutan en un servidor remoto
  • Remote – WSL: Conecta con aplicaciones que se ejecutan en el Subsistema de Windows para Linux (WSL).

Otras opciones de depuración de Node.js

La Guía de depuración de Node.js ofrece consejos para una serie de editores de texto e IDEs, como Visual Studio, JetBrains WebStorm, Gitpod y Eclipse. Atom ofrece una extensión node-debug, que integra el depurador DevTools de Chrome en el editor.

Una vez que tu aplicación esté en funcionamiento, puedes considerar el uso de servicios comerciales de depuración como LogRocket y Sentry.io, que pueden grabar y reproducir los errores del cliente y del servidor encontrados por usuarios reales.

Resumen

Históricamente, la depuración de JavaScript ha sido difícil, pero ha habido grandes mejoras en la última década. Las opciones son tan buenas -si no mejores- que las que se ofrecen para otros lenguajes.

Utiliza cualquier herramienta que sea práctica para localizar un problema. No hay nada malo en usar console.log() para la búsqueda rápida de errores, pero Chrome DevTools o VS Code pueden ser preferibles para problemas más complejos. Las herramientas pueden ayudarte a crear un código más robusto, y pasarás menos tiempo arreglando fallos.

¿Qué práctica de depuración de Node.js utilizas tú? ¡Compártela en la sección de comentarios más abajo!

Craig Buckler

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