wandres.dev
SOURCES I · Depurar con breakpoints

Anatomía del panel de Sources

Las cinco secciones del navegador de ficheros, la navegación por nombre y por símbolo, y qué código estás viendo realmente cuando abres un fichero.

⏱ 14 min

Sources es el panel con más superficie de todas las DevTools y el que más gente usa solo para una cosa: leer un fichero. Tiene cinco árboles distintos con contenidos de naturaleza muy diferente, un editor con navegación por símbolos, y un depurador completo con seis subpaneles. Empezar por conocer qué hay dónde evita el desconcierto de abrir un fichero que no es el que se está ejecutando, que es un error mucho más frecuente de lo que parece.

🎯 Al terminar esta lección sabrás
  • Distinguir las cinco secciones del navegador de ficheros y qué contiene cada una.
  • Abrir un fichero y saltar a un símbolo o a una línea sin usar el ratón.
  • Formatear código minificado y entender qué implica para los breakpoints.
  • Verificar que el fichero que estás viendo es el que se está ejecutando.

Las cinco secciones

Página. El árbol de todos los recursos que el navegador ha cargado para este documento, organizados por origen y por ruta. Incluye el HTML, los scripts, las hojas de estilo, las imágenes y las fuentes. Si hay source maps, aparece además un árbol paralelo con los ficheros originales reconstruidos. Los iframes tienen su propia rama, y los workers también.

Sistema de ficheros. Carpetas locales que hayas conectado como espacio de trabajo. Editarlas escribe en disco de verdad.

Overrides. Ficheros locales que sustituyen a los que llegan de la red. Persisten entre sesiones.

Scripts de contenido. El código inyectado por las extensiones. Es una sección que conviene mirar una vez en cualquier página, para calibrar cuánto código ajeno se está ejecutando en tu perfil.

Snippets. Fragmentos guardados, ejecutables en cualquier página. Tienen nivel propio en esta guía.

ℹ️
Nota

El árbol de Página muestra los recursos tal como los pidió el navegador, así que un bundle de tres megas aparece como un solo fichero enorme. Los ficheros que ves con nombres de tu proyecto vienen de source maps y no existen en el servidor: son reconstrucciones. Esa distinción es la clave del nivel dedicado a los mapas.

Abrir un fichero por nombre. Cmd+P o Ctrl+P, con búsqueda difusa sobre todos los recursos cargados. Es la vía normal; navegar el árbol con el ratón es para explorar, no para llegar.

Saltar a un símbolo. Escribiendo @ en ese mismo diálogo aparece la lista de funciones y clases del fichero abierto. En un fichero de dos mil líneas es la única forma razonable de moverse.

Ir a una línea. Con : seguido del número, o con Ctrl+G.

Buscar en el fichero. Cmd+F o Ctrl+F, con soporte de expresiones regulares.

Buscar en todos los ficheros. Cmd+Opt+F o Ctrl+Shift+F. Rastrea todo el código descargado, incluidas las librerías. Es la forma más rápida de encontrar quién produce una cadena de texto concreta cuando no sabes ni en qué módulo mirar.

Pretty print y lo que implica

El botón de llaves en la barra inferior del editor reformatea código minificado en algo legible. Genera un fichero virtual con sufijo que indica que está formateado.

Lo importante es lo que ocurre con los breakpoints. En código minificado, una línea puede contener veinte sentencias, así que un breakpoint de línea es inútil: se detiene al principio de todo y no puedes elegir en qué parte. Con el formateo, cada sentencia tiene su línea y el breakpoint se puede colocar con precisión. Las DevTools mantienen la correspondencia entre el fichero formateado y el real, así que el breakpoint funciona sobre el código que de verdad se ejecuta.

Cuando hay source map, el formateo casi nunca hace falta porque ya estás viendo el fuente original. Cuando no lo hay —una librería de terceros, un script de un proveedor, código de producción sin mapas— el formateo es la única vía.

Verificar que estás viendo el código correcto

El error que más tiempo desperdicia en este panel. Hay tres formas de acabar mirando código que no se está ejecutando.

Un source map desactualizado, que reconstruye una versión anterior del fichero. El síntoma es que el código que ves no cuadra con el comportamiento, o que un breakpoint se detiene en una línea que no tiene sentido.

Un fichero cacheado, servido desde la caché mientras el servidor ya tiene otro. El panel de red lo confirma.

Un override activo que sustituye el fichero de red por uno local que escribiste hace semanas. El fichero aparece marcado, pero es fácil no fijarse.

La verificación definitiva no está en el editor sino en la evaluación. Con la ejecución detenida en la función que te interesa, esta expresión en la consola devuelve el código realmente cargado.

// El codigo real de la funcion en la que estas, sin pasar por ningun mapa
console.log(String(nombreDeLaFuncion));

Si lo que devuelve no se parece a lo que ves en el editor, tienes uno de los tres casos y ya sabes por dónde seguir.

Los subpaneles del depurador

A la derecha del editor —o debajo, según la disposición— vive el depurador, con seis secciones que se despliegan por separado.

Watch, las expresiones vigiladas. Breakpoints, la lista completa con casillas para activar y desactivar. Scope, las variables accesibles en el marco seleccionado. Call stack, la pila de llamadas. XHR y fetch breakpoints, DOM breakpoints, Global listeners y Event listener breakpoints, que son las cuatro familias de puntos de parada sin línea.

Las cuatro últimas son el contenido del nivel siguiente y son, con diferencia, la parte de las DevTools con mejor relación entre lo poco que se conoce y lo mucho que resuelve.

Depurar es más rápido que instrumentar, y todo el mundo hace lo contrario

Existe una asimetría llamativa en cómo la gente depura: la mayoría de los desarrolladores que llevan años trabajando con JavaScript siguen resolviendo los problemas con trazas y prácticamente no usan el depurador, y cuando se les pregunta la razón suele ser alguna variante de “es más rápido poner un log”. Merece la pena hacer las cuentas, porque no lo es. Una traza cuesta una edición, un guardado, una recompilación, una recarga y una reproducción del bug —entre quince segundos y dos minutos según el proyecto— y devuelve un dato: el valor de lo que decidiste loguear en el punto que elegiste. Si resulta que necesitas otro valor, o el mismo valor dos líneas más arriba, se repite el ciclo entero. Un breakpoint cuesta un clic y devuelve todo el estado del programa en ese instante: todas las variables locales, todos los closures, toda la cadena de llamadas con sus argumentos, y la posibilidad de evaluar cualquier expresión en ese contexto exacto. Y si te has equivocado de sitio, mover el punto cuesta otro clic sin recompilar nada. La diferencia no es de un veinte por ciento: es de un orden de magnitud, y crece con la dificultad del bug, porque los bugs difíciles son precisamente aquellos en los que no sabes de antemano qué valor necesitas mirar. Entonces, ¿por qué la gente prefiere las trazas? Por dos razones que conviene reconocer para superarlas. La primera es que el depurador exige formular una hipótesis antes de mirar, y eso es incómodo; poner un log se siente como hacer algo, mientras que pensar dónde poner el breakpoint se siente como no avanzar. La segunda es que el depurador tiene una curva de aprendizaje de una tarde, con seis subpaneles cuyo propósito no es obvio, y esa tarde nunca es hoy. Los cuatro niveles que siguen son esa tarde, y el más rentable de todos es el que empieza justo después de este.