Depuração da Web moderna no Chrome DevTools

Introdução

Atualmente, os autores podem usar muitas abstrações para criar seus aplicativos da Web. Em vez de interagir diretamente com as APIs de nível inferior que a plataforma Web fornece, muitos autores aproveitam estruturas, ferramentas de compilação e compiladores para escrever seus aplicativos a partir de uma perspectiva de nível superior.

Por exemplo, os componentes criados com base no framework do Angular são criados no TypeScript com modelos HTML. Em segundo plano, a CLI Angular e o webpack compilam tudo para JavaScript e em um chamado bundle, que é enviado ao navegador.

Ao depurar ou criar perfis de aplicativos da Web no DevTools, você atualmente consegue ver e depurar essa versão compilada do seu código, em vez do código que você realmente escreveu. No entanto, como autor, você não quer:

  • Você não quer depurar o código JavaScript minificado, e sim o código JavaScript original.
  • Ao usar o TypeScript, você não quer depurar o JavaScript, e sim seu código original do TypeScript.
  • Ao usar modelos como Angular, Lit ou JSX, nem sempre é recomendado depurar o DOM resultante. Talvez você queira depurar os componentes em si.

Em geral, é recomendável depurar seu próprio código da forma como você o escreveu.

Embora os mapas de origem já preencham essa lacuna, há muito mais que o Chrome DevTools e o ecossistema podem fazer nessa área.

Vamos dar uma olhada.

Código criado x código implantado

Atualmente, ao navegar pela árvore de arquivos no painel Sources, você pode ver o conteúdo do pacote compilado e muitas vezes minificado. Esses são os arquivos reais que o navegador baixa e executa. O DevTools chama isso de Código implantado.

Captura de tela da árvore de arquivos no Chrome DevTools mostrando o código implantado.

Isso não é muito útil e muitas vezes difícil de entender. Como autor, você quer ver e depurar o código que escreveu, não o Código implantado.

Para compensar, você pode fazer com que a árvore mostre o Código de criação. Isso torna a árvore mais parecida com os arquivos de origem que você vê no ambiente de desenvolvimento integrado, e esses arquivos agora estão separados do Código implantado.

Captura de tela da árvore de arquivos no Chrome DevTools mostrando o código de criação.

Para ativar essa opção no Chrome DevTools, acesse Configurações > Experimentos e marque Agrupar origens em árvores criadas e implantadas.

Captura de tela das configurações do DevTools.

"Apenas meu código"

Ao usar dependências ou criar com base em um framework, os arquivos de terceiros podem atrapalhar. Na maioria das vezes, você quer ver apenas o código, e não o de alguma biblioteca de terceiros escondida na pasta node_modules.

Para compensar, o DevTools tem uma configuração extra ativada por padrão: Adicionar automaticamente scripts conhecidos de terceiros à lista de ignorados. Ele pode ser encontrado em DevTools > Configurações > Lista de ignorados.

Captura de tela das configurações do DevTools.

Com essa configuração ativada, o DevTools oculta qualquer arquivo ou pasta que um framework ou uma ferramenta de build tenha marcado como para ignorar.

A partir do Angular v14.1.0, o conteúdo das pastas node_modules e webpack foi marcado dessa forma. Portanto, essas pastas, os arquivos dentro delas e outros artefatos de terceiros não aparecem em vários locais no DevTools.

Como autor, você não precisa fazer nada para ativar esse novo comportamento. A implementação dessa mudança depende da estrutura.

Ignorar código listado em stack traces

Os stack traces não são mais exibidos quando esses arquivos na lista de ignorados não são mais exibidos. Como autor, agora você verá stack traces mais relevantes.

Captura de tela de um stack trace no DevTools.

Para ver todos os frames de chamada do stack trace, clique no link Mostrar mais frames.

O mesmo se aplica às pilhas de chamadas que você vê ao depurar e analisar seu código. Quando frameworks ou bundlers informam ao DevTools sobre scripts de terceiros, o DevTools oculta automaticamente todos os frames de chamada irrelevantes e pula qualquer código incluído na lista de ignorados durante a depuração da etapa.

Captura de tela do Depurador de origens do DevTools durante a depuração.

Código de lista de ignorados na árvore de arquivos

Para ocultar as pastas e os arquivos que estão na lista de ignorados da árvore de arquivos Código de criação no painel Fontes, marque Ocultar código da lista de ignorados na visualização em árvore de origens em Configurações > Experimentos no DevTools.

Captura de tela das configurações do DevTools.

No projeto Angular de exemplo, as pastas node_modules e webpack agora estão ocultas.

Captura de tela da árvore de arquivos no Chrome DevTools mostrando o código de criação, mas não mostrando node_modules.

Código de lista de ignorados no menu "Acesso rápido"

O código da lista ignorada não fica apenas oculto na árvore de arquivos, mas também no menu “Quick Open” (Control + P (Linux/Windows) ou Command + P (Mac)).

Captura de tela do DevTools com o menu “Quick Open”.

Mais melhorias nos stack traces

Depois de abordar os stack traces relevantes, o Chrome DevTools apresenta ainda mais melhorias para eles.

Stack traces vinculados

Quando algumas operações estão programadas para acontecer de maneira assíncrona, os stack traces no DevTools atualmente contam apenas parte da história.

Por exemplo, este é um programador muito simples em um arquivo 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();

... e como um desenvolvedor pode usá-la no próprio código em um arquivo example.js:

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

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

businessLogic();

Ao adicionar um ponto de interrupção dentro do método someTask ou inspecionar o rastro impresso no console, você não vê nenhuma menção à chamada businessLogic() que foi a "causa raiz" dessa operação.

Em vez disso, você vê apenas a lógica de programação do framework que levou à execução da tarefa e nenhuma navegação estrutural no stack trace para ajudar a descobrir os vínculos causais entre os eventos que levam à tarefa.

Um stack trace de um código assíncrono executado sem informações sobre quando ele foi programado.

Graças a um novo recurso chamado "Async Stack Tagging", é possível contar toda a história vinculando as duas partes do código assíncrono.

A API Async Stack Tagging traz um novo método console, chamado console.createTask(). A assinatura da API é a seguinte:

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

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

A chamada console.createTask() retorna uma instância Task que pode ser usada depois para executar o conteúdo f da tarefa.

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

// Task Execution
task.run(f);

A tarefa forma o vínculo entre o contexto em que foi criada e o contexto da função assíncrona que está sendo executada.

Aplicado à função makeScheduler acima, o código se torna o seguinte:

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();
      }
    },
  };
}

Graças a isso, o Chrome DevTools agora pode mostrar um stack trace melhor.

Um stack trace de um código assíncrono executado com informações sobre quando ele foi programado.

Observe como o businessLogic() agora está incluído no stack trace. Além disso, a tarefa tem um nome conhecido, someTask, em vez do requestAnimationFrame genérico, como antes.

Frames de chamada amigáveis

Os frameworks geralmente geram códigos de todos os tipos de linguagens de modelo ao construir um projeto, como modelos Angular ou JSX que transformam código HTML em JavaScript simples que é executado no navegador. Às vezes, esses tipos de funções geradas recebem nomes pouco amigáveis, como nomes com uma única letra depois de minificados ou alguns nomes obscuros ou desconhecidos, mesmo quando não são.

No projeto de exemplo, um exemplo disso é a AppComponent_Template_app_button_handleClick_1_listener, que aparece no stack trace.

Captura de tela do stack trace com o nome de uma função gerado automaticamente.

Para resolver isso, o Chrome DevTools agora oferece suporte para renomear essas funções usando mapas de origem. Se um mapa de origem tiver uma entrada de nome para o início de um escopo de função, o frame de chamada precisará exibir esse nome no stack trace.

Como autor, você não precisa fazer nada para ativar esse novo comportamento. A implementação dessa mudança depende da estrutura.

No futuro

Graças às adições destacadas nesta postagem, o Chrome DevTools pode oferecer uma melhor experiência de depuração. Há mais áreas que a equipe gostaria de explorar. Em particular, como melhorar a experiência de criação de perfil no DevTools.

A equipe do Chrome DevTools incentiva os autores da estrutura a adotar esses novos recursos. O Estudo de caso: Melhor depuração Angular com DevTools (link em inglês) oferece orientações sobre como implementar isso.