Estudo de caso: melhor depuração angular com o DevTools

Uma experiência de depuração melhorada

Nos últimos meses, a equipe do Chrome DevTools colaborou com a equipe do Angular para lançar melhorias na experiência de depuração no Chrome DevTools. Pessoas das duas equipes trabalharam juntas e tomaram medidas para permitir que os desenvolvedores debuguem e criem perfis de aplicativos da Web na perspectiva de criação: em termos de linguagem de origem e estrutura do projeto, com acesso a informações conhecidas e relevantes para eles.

Esta postagem mostra quais mudanças no Angular e no Chrome DevTools foram necessárias para isso. Embora algumas dessas mudanças sejam demonstradas pelo Angular, elas também podem ser aplicadas a outros frameworks. A equipe do Chrome DevTools incentiva outros frameworks a adotar as novas APIs do console e os pontos de extensão do mapa de origem para que eles também possam oferecer uma melhor experiência de depuração aos usuários.

Código de lista de ignorados

Ao depurar aplicativos usando o Chrome DevTools, os autores geralmente querem apenas o código deles, não o do framework ou alguma dependência escondida na pasta node_modules.

Para isso, a equipe do DevTools introduziu uma extensão para mapas de origem, chamada x_google_ignoreList. Essa extensão é usada para identificar fontes de terceiros, como código de framework ou código gerado pelo bundler. Quando um framework usa essa extensão, os autores agora evitam automaticamente o código que não querem ver ou percorrer sem precisar configurar isso manualmente com antecedência.

Na prática, o Chrome DevTools pode ocultar automaticamente o código identificado como tal em stack traces, na árvore de fontes, na caixa de diálogo "Abrir rapidamente" e também melhorar o comportamento de execução e retomada no depurador.

Um GIF animado mostrando o DevTools antes e depois. Observe como, na imagem depois, as Ferramentas do desenvolvedor mostram o código criado pelo autor na árvore, não sugerem mais nenhum dos arquivos do framework no menu "Abrir rapidamente" e mostram um stack trace muito mais limpo à direita.

A extensão do mapa de origem x_google_ignoreList

Nos mapas de origem, o novo campo x_google_ignoreList se refere à matriz sources e lista os índices de todas as fontes de terceiros conhecidas nesse mapa. Ao analisar o mapa de origem, as Ferramentas para desenvolvedores do Chrome vão usar isso para descobrir quais seções do código devem ser ignoradas.

Confira abaixo um mapa de origem para um arquivo out.js gerado. Há dois sources originais que contribuíram para gerar o arquivo de saída: foo.js e lib.js. O primeiro é algo que um desenvolvedor de sites escreveu, e o segundo é um framework que ele usou.

{
  "version" : 3,
  "file": "out.js",
  "sourceRoot": "",
  "sources": ["foo.js", "lib.js"],
  "sourcesContent": ["...", "..."],
  "names": ["src", "maps", "are", "fun"],
  "mappings": "A,AAAB;;ABCDE;"
}

O sourcesContent é incluído para essas duas origens originais, e o Chrome DevTools mostra esses arquivos por padrão no depurador:

  • Como arquivos na árvore "Fontes".
  • Como resultados na caixa de diálogo "Abrir rapidamente".
  • Como locais de quadro de chamada mapeados em rastreamentos de pilha de erros enquanto pausados em um ponto de interrupção e durante a execução.

Agora é possível incluir mais uma informação nos mapas de origem para identificar quais delas são códigos próprios ou de terceiros:

{
  ...
  "sources": ["foo.js", "lib.js"],
  "x_google_ignoreList": [1],
  ...
}

O novo campo x_google_ignoreList contém um único índice que se refere à matriz sources: 1. Isso especifica que as regiões mapeadas para lib.js são, na verdade, códigos de terceiros que precisam ser adicionados automaticamente à lista de ignorados.

Em um exemplo mais complexo, mostrado abaixo, os índices 2, 4 e 5 especificam que as regiões mapeadas para lib1.ts, lib2.coffee e hmr.js são códigos de terceiros que precisam ser adicionados automaticamente à lista de ignorados.

{
  ...
  "sources": ["foo.html", "bar.css", "lib1.ts", "baz.js", "lib2.coffee", "hmr.js"],
  "x_google_ignoreList": [2, 4, 5],
  ...
}

Se você é um desenvolvedor de framework ou bundler, verifique se os mapas de origem gerados durante o processo de build incluem esse campo para se conectar a esses novos recursos no Chrome DevTools.

x_google_ignoreList no Angular

A partir da Angular v14.1.0, o conteúdo das pastas node_modules e webpack foi marcado como “para ignorar”.

Isso foi feito com uma mudança no angular-cli criando um plug-in que se conecta ao módulo Compiler do webpack

O plug-in do webpack criado pelos nossos engenheiros se conecta ao estágio PROCESS_ASSETS_STAGE_DEV_TOOLING e preenche o campo x_google_ignoreList nos mapas de origem dos recursos finais gerados pelo webpack e carregados pelo navegador.

const map = JSON.parse(mapContent) as SourceMap;
const ignoreList = [];

for (const [index, path] of map.sources.entries()) {
  if (path.includes('/node_modules/') || path.startsWith('webpack/')) {
    ignoreList.push(index);
  }
}

map[`x_google_ignoreList`] = ignoreList;
compilation.updateAsset(name, new RawSource(JSON.stringify(map)));

Stack traces vinculados

Os Stack Traces respondem à pergunta “como cheguei aqui”, mas muitas vezes isso é da perspectiva da máquina e não necessariamente algo que corresponda à perspectiva do desenvolvedor ou ao modelo mental dele do tempo de execução do aplicativo. Isso é especialmente verdadeiro quando algumas operações são programadas para ocorrer de forma assíncrona mais tarde: ainda pode ser interessante saber a "causa raiz" ou o lado da programação dessas operações, mas isso é exatamente algo que não faz parte de um stack trace assíncrono.

O V8 tem um mecanismo interno para acompanhar essas tarefas assíncronas quando são usadas primitivas de programação padrão do navegador, como setTimeout. Isso é feito por padrão nesses casos, para que os desenvolvedores possam inspecionar esses dados. Mas, em projetos mais complexos, não é tão simples assim, especialmente quando se usa uma estrutura com mecanismos de programação mais avançados, por exemplo, que realiza rastreamento de zona, enfileiramento de tarefas personalizadas ou que divide atualizações em várias unidades de trabalho executadas ao longo do tempo.

Para resolver isso, as Ferramentas do desenvolvedor expõem um mecanismo chamado "API de inclusão de marcação de pilha assíncrona" no objeto console, que permite que os desenvolvedores de framework indiquem os locais em que as operações são programadas e executadas.

API Async Stack Tagging

Sem a inclusão de tags de pilha assíncrona, os rastreamentos de pilha para código executado de forma assíncrona de maneira complexa por frameworks aparecem sem conexão com o código em que foram programados.