Depuração da Web moderna no Chrome DevTools

Introdução

Atualmente, os autores podem usar muitas abstrações para criar aplicativos da Web. Em vez de fazer uma interface direta 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 de uma perspectiva de nível superior.

Por exemplo, os componentes criados no framework Angular são criados no TypeScript com modelos HTML. Por trás de tudo, a CLI Angular e o webpack compilam tudo para JavaScript e em um chamado bundle (pacote), que é enviado ao navegador.

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

  • Você não quer depurar o código JavaScript minificado, mas sim o código JavaScript original.
  • Ao usar o TypeScript, não convém depurar o JavaScript, mas o código original do TypeScript.
  • Ao usar modelos como com Angular, Lit ou JSX, nem sempre você quer depurar o DOM resultante. É possível depurar os próprios componentes.

No geral, é provável que você queira depurar seu próprio código da maneira 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 versus código implantado

Atualmente, ao navegar pela árvore de arquivos no painel Origens, você pode conferir o conteúdo do pacote compilado e, geralmente, minimizado. Esses são os arquivos reais transferidos por download e executados pelo navegador. O DevTools chama isso de Deployed Code.

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, agora é possível fazer com que a árvore mostre o Authored Code. Isso torna a árvore mais semelhante aos arquivos de origem que você vê no seu 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 criado.

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ê só quer ver apenas o código, e não o código de uma biblioteca de terceiros escondida na pasta node_modules.

Para compensar, o DevTools tem uma configuração extra ativada por padrão: Adicionar automaticamente scripts de terceiros conhecidos à lista de ignorados. Você pode encontrá-lo em DevTools > Settings > Ignore List.

Captura de tela das configurações do DevTools.

Com essa configuração ativada, o DevTools oculta qualquer arquivo ou pasta marcado por um framework ou ferramenta de build 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. Cabe ao framework implementar essa mudança.

Códigos ignorados em stack traces

Um local em que esses arquivos da lista de ignorados não aparecem mais é nos stack traces. Como autor, agora você pode conferir 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 Show more 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, ele oculta automaticamente todos os frames de chamada irrelevantes e pula qualquer código na lista de ignorados durante a depuração por etapas.

Captura de tela do Debugger Sources do DevTools durante a depuração.

Código ignorado na árvore de arquivos

Para ocultar os arquivos e pastas da lista de ignorados da árvore de arquivos Authored Code no painel Fontes, marque Ocultar código da lista de ignorados na visualização da árvore de origens em Settings > Experiments no DevTools.

Captura de tela das configurações do DevTools.

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

Captura de tela da árvore de arquivos no Chrome DevTools mostrando o código criado, mas sem node_modules.

Código da lista de ignorados no menu "Abertura rápida"

O código de 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 introduz ainda mais melhorias neles.

Stack traces vinculados

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

Por exemplo, aqui está um agendador 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 ao inspecionar o rastro impresso no console, você não vai notar nenhuma menção à chamada businessLogic() que era 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 a essa tarefa.

Um stack trace de algum código executado de maneira assíncrona 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 apresenta um novo método console chamado console.createTask(). A assinatura da API fica assim:

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 mais tarde para executar o f de conteúdo 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 executado de maneira assíncrona com informações sobre quando ele foi programado.

Observe como 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 ligação compatíveis

As estruturas muitas vezes geram código a partir de todos os tipos de linguagens de modelos ao construir um projeto, como os modelos Angular ou JSX, que transformam código HTML em JavaScript simples que, eventualmente, é executado no navegador. Às vezes, esses tipos de funções geradas recebem nomes não muito amigáveis: nomes de letras únicas após serem minimizadas ou alguns nomes obscuros ou desconhecidos, mesmo quando não são.

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

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

Para resolver isso, o Chrome DevTools agora oferece suporte à renomeação dessas funções pelos 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. Cabe ao framework implementar essa mudança.

No futuro

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

A equipe do Chrome DevTools incentiva os autores de framework a adotar esses novos recursos. O estudo de caso: melhor depuração angular com o DevTools (em inglês) oferece orientações sobre como implementar isso.