Depuración web moderna en Herramientas para desarrolladores de Chrome

Introducción

Hoy en día, los autores pueden usar muchas abstracciones para compilar sus aplicaciones web. En lugar de interactuar directamente con las APIs de nivel inferior que proporciona la plataforma web, muchos autores aprovechan los frameworks, las herramientas de compilación y los compiladores para escribir sus aplicaciones desde una perspectiva de nivel superior.

Por ejemplo, los componentes compilados sobre el framework de Angular se crean en TypeScript con plantillas HTML. De forma interna, la CLI y el paquete web de Angular compilan todo en JavaScript y en un llamado paquete, que luego se envía al navegador.

Cuando depuras o perfilas aplicaciones web en Herramientas para desarrolladores, actualmente puedes ver y depurar esta versión compilada de tu código en lugar del código que escribiste. Sin embargo, como autor, esto no es lo que deseas, aunque:

  • No quieres depurar código JavaScript reducido, debes depurar tu código JavaScript original.
  • Cuando usas TypeScript, no quieres depurar JavaScript, sino que debes depurar tu código original de TypeScript.
  • Cuando usas plantillas, como con Angular, Lit o JSX, no siempre es recomendable depurar el DOM resultante. Tal vez sea conveniente que depures los componentes.

En general, es probable que desees depurar tu propio código tal como lo escribiste.

Si bien los mapas de fuentes ya cierran esta brecha en cierta medida, hay más que las Herramientas para desarrolladores de Chrome y el ecosistema pueden hacer en esta área.

Veamos las diferencias.

Código creado frente a código implementado

Actualmente, cuando navegas por el árbol de archivos en el Panel de fuentes, puedes ver el contenido del paquete compilado (y, a menudo, reducido). Son los archivos reales que descarga y ejecuta el navegador. Las Herramientas para desarrolladores lo llaman código implementado.

Captura de pantalla del árbol de archivos en las Herramientas para desarrolladores de Chrome que muestra el código implementado.

No es muy práctico y suele ser difícil de comprender. Como autor, deseas ver y depurar el código que escribiste, no el código implementado.

Para compensarlo, ahora puedes hacer que el árbol muestre el Código de autor en su lugar. Esto hace que el árbol se parezca más a los archivos de origen que puedes ver en tu IDE, y estos archivos ahora están separados del código implementado.

Captura de pantalla del árbol de archivos en las Herramientas para desarrolladores de Chrome que muestra el código de autor.

Para habilitar esta opción en las Herramientas para desarrolladores de Chrome, ve a Configuración > Experimentos y marca la opción Agrupar fuentes en árboles implementados y creados.

Captura de pantalla de la Configuración de Herramientas para desarrolladores.

"Solo mi código"

Cuando usas dependencias o compilas sobre un framework, es posible que los archivos de terceros interfieran en tu camino. La mayoría de las veces, solo quieres ver tu código y no el de alguna biblioteca de terceros escondida en la carpeta node_modules.

Para compensarlo, las Herramientas para desarrolladores tienen un parámetro de configuración adicional habilitado de forma predeterminada: Agregar automáticamente secuencias de comandos de terceros conocidas a la lista de elementos ignorados. Puedes encontrarla en DevTools > Configuración > Lista de elementos ignorados:

Captura de pantalla de la Configuración de Herramientas para desarrolladores.

Con esta configuración habilitada, Herramientas para desarrolladores oculta cualquier archivo o carpeta que un framework o una herramienta de compilación hayan marcado como para ignorarlos.

A partir de la versión 14.1.0 de Angular, el contenido de sus carpetas node_modules y webpack se marcó como tal. Por lo tanto, estas carpetas, los archivos dentro de ellas y otros artefactos de terceros no aparecen en varios lugares en Herramientas para desarrolladores.

Como autor, no necesitas hacer nada para habilitar este nuevo comportamiento. La implementación de este cambio depende del framework.

Código incluido en la lista de elementos ignorados en seguimientos de pila

Un lugar donde estos archivos de la lista de elementos ignorados ya no aparecen es en los seguimientos de pila. Como autor, ahora puedes ver más seguimientos de pila relevantes.

Captura de pantalla de un seguimiento de pila en Herramientas para desarrolladores.

Si deseas ver todos los marcos de llamada del seguimiento de pila, puedes hacer clic en el vínculo Show more frame en cualquier momento.

Lo mismo se aplica a las pilas de llamadas que ves mientras depuras y recorres el código. Cuando los frameworks o agrupadores informan a las Herramientas para desarrolladores sobre secuencias de comandos de terceros, las Herramientas para desarrolladores ocultan automáticamente todos los marcos de llamadas irrelevantes y saltan sobre cualquier código que se haya ignorado durante la depuración por pasos.

Captura de pantalla del depurador de fuentes de Herramientas para desarrolladores durante la depuración.

Código incluido en la lista de elementos ignorados en el árbol de archivos

Para ocultar los archivos y las carpetas de la lista de elementos ignorados del árbol de archivos Authored Code del panel Sources, marca la opción Ocultar el código de la lista de elementos ignorados en la vista de árbol de fuentes en Configuración > Experimentos en Herramientas para desarrolladores.

Captura de pantalla de la Configuración de Herramientas para desarrolladores.

En el proyecto de muestra de Angular, las carpetas node_modules y webpack ahora están ocultas.

Captura de pantalla del árbol de archivos en las Herramientas para desarrolladores de Chrome que muestra el código creado, pero no node_modules.

Código incluido en la lista de elementos ignorados en el menú "Quick Open"

El código omitido no solo se oculta del árbol de archivos, sino que también se oculta en el menú "Quick Open" (Control + P (Linux/Windows) o Comando + P (Mac)).

Captura de pantalla de Herramientas para desarrolladores con el menú “Quick Open”.

Más mejoras en los seguimientos de pila

Ahora que ya abordamos los seguimientos de pila relevantes, las Herramientas para desarrolladores de Chrome presentan aún más mejoras en ellos.

Seguimientos de pila vinculados

Cuando algunas operaciones están programadas para realizarse de forma asíncrona, actualmente los seguimientos de pila en Herramientas para desarrolladores solo cuentan una parte de la historia.

Por ejemplo, aquí hay un programador muy simple en un archivo framework.js hipotético:

function makeScheduler() {
  const tasks = [];

  return {
    schedule(f) {
      tasks.push({ f });
    },

    work() {
      while (tasks.length) {
        const { f } = tasks.shift();
        f();
      }
    },
  };
}

const scheduler = makeScheduler();

function loop() {
  scheduler.work();
  requestAnimationFrame(loop);
};

loop();

y cómo un desarrollador podría usarla en su propio código, en un archivo example.js:

function someTask() {
  console.trace("done!");
}

function businessLogic() {
  scheduler.schedule(someTask);
}

businessLogic();

Cuando se agrega un punto de interrupción dentro del método someTask o cuando se inspecciona el seguimiento impreso en la consola, no ves ninguna mención de la llamada a businessLogic() que fue la “causa raíz” de esta operación.

En cambio, solo ves la lógica de programación del framework que condujo a la ejecución de la tarea y ninguna ruta de navegación en el seguimiento de pila para ayudarte a descubrir los vínculos causales entre los eventos que conducen a esta tarea.

Seguimiento de pila de algún código asíncrono ejecutado sin información sobre cuándo se programó.

Gracias a una nueva función llamada "Etiquetado de pilas asíncronos", es posible contar la historia completa después de todo vinculando ambas partes del código asíncrono.

La API de Async Stack Tagging presenta un nuevo método console llamado console.createTask(). La firma de la API es la siguiente:

interface Console {
  createTask(name: string): Task;
}

interface Task {
  run<T>(f: () => T): T;
}

La llamada a console.createTask() muestra una instancia de Task que puedes usar más adelante para ejecutar el f del contenido de la tarea.

// Task Creation
const task = console.createTask(name);

// Task Execution
task.run(f);

La tarea forma el vínculo entre el contexto en el que se creó y el contexto de la función asíncrona que se está ejecutando.

Cuando se aplica a la función makeScheduler anterior, el código se convierte en el siguiente:

function makeScheduler() {
  const tasks = [];

  return {
    schedule(f) {
      const task = console.createTask(f.name);
      tasks.push({ task, f });
    },

    work() {
      while (tasks.length) {
        const { task, f } = tasks.shift();
        task.run(f); // instead of f();
      }
    },
  };
}

Gracias a esto, las Herramientas para desarrolladores de Chrome ahora pueden mostrar un mejor seguimiento de pila.

Seguimiento de pila de algún código asíncrono ejecutado con información sobre cuándo se programó.

Observa que ahora se incluye businessLogic() en el seguimiento de pila. No solo eso, sino que la tarea tiene un nombre familiar someTask en lugar del requestAnimationFrame genérico, como antes.

Marcos de llamadas amigables

Los frameworks suelen generar código a partir de todo tipo de lenguajes de plantilla cuando se compila un proyecto, como las plantillas de Angular o JSX que convierten código de aspecto HTML en JavaScript simple que, finalmente, se ejecuta en el navegador. A veces, estos tipos de funciones generadas reciben nombres poco amigables, como nombres con una sola letra después de su reducción o nombres oscuros o desconocidos, incluso cuando no lo son.

En el proyecto de muestra, puedes ver AppComponent_Template_app_button_handleClick_1_listener como ejemplo en el seguimiento de pila.

Captura de pantalla de un seguimiento de pila con un nombre de función generado automáticamente.

Para solucionar este problema, las Herramientas para desarrolladores de Chrome ahora admiten el cambio de nombre de estas funciones a través de mapas de origen. Si un mapa de orígenes tiene una entrada de nombre para el inicio del alcance de una función, el marco de llamada debe mostrar ese nombre en el seguimiento de pila.

Como autor, no necesitas hacer nada para habilitar este nuevo comportamiento. La implementación de este cambio depende del framework.

Con la mirada puesta en el futuro

Gracias a las adiciones descritas en esta publicación, las Herramientas para desarrolladores de Chrome pueden ofrecerte una mejor experiencia de depuración. Hay más áreas que al equipo le gustaría explorar. En particular, cómo mejorar la experiencia de generación de perfiles en Herramientas para desarrolladores.

El equipo de Herramientas para desarrolladores de Chrome alienta a los autores de frameworks a adoptar estas nuevas capacidades. En el caso de éxito: Mejor depuración de Angular con Herramientas para desarrolladores, se ofrece orientación para implementarlo.