Moderne webfoutopsporing in Chrome DevTools

Invoering

Tegenwoordig kunnen auteurs veel abstracties gebruiken om hun webapplicaties te bouwen. In plaats van rechtstreeks te communiceren met de API's op een lager niveau die het webplatform biedt, maken veel auteurs gebruik van raamwerken, bouwen ze tools en compilers om hun applicaties vanuit een hoger perspectief te schrijven.

Componenten die bovenop het Angular-framework zijn gebouwd, zijn bijvoorbeeld geschreven in TypeScript met HTML-sjablonen. Onder de motorkap compileren de Angular CLI en webpack alles naar JavaScript en in een zogenaamde bundel , die vervolgens naar de browser wordt verzonden.

Bij het debuggen of profileren van webapplicaties in DevTools krijgt u momenteel deze gecompileerde versie van uw code te zien en te debuggen in plaats van de code die u daadwerkelijk heeft geschreven. Als auteur wil je dit echter niet:

  • U wilt geen fouten opsporen in verkleinde JavaScript-code, u wilt fouten opsporen in uw originele JavaScript-code.
  • Wanneer u TypeScript gebruikt, wilt u geen fouten in JavaScript debuggen, u wilt fouten in uw originele TypeScript-code debuggen.
  • Wanneer u sjablonen gebruikt zoals bij Angular, Lit of JSX, wilt u niet altijd fouten opsporen in de resulterende DOM. Misschien wilt u de componenten zelf debuggen.

Over het algemeen wilt u waarschijnlijk uw eigen code debuggen terwijl u deze schreef .

Hoewel bronkaarten deze kloof al tot op zekere hoogte kunnen dichten, is er meer dat Chrome DevTools en het ecosysteem op dit gebied kunnen doen.

Laten we kijken!

Geschreven versus geïmplementeerde code

Momenteel krijgt u bij het navigeren door de bestandsboom in het Bronnenpaneel de inhoud van de gecompileerde (en vaak verkleinde) bundel te zien. Dit zijn de daadwerkelijke bestanden die de browser downloadt en uitvoert. DevTools noemt dit de geïmplementeerde code .

Schermafbeelding van de bestandsstructuur in Chrome DevTools met de geïmplementeerde code.

Dit is niet erg handig en vaak moeilijk te begrijpen. Als auteur wil je de code die je hebt geschreven zien en er fouten in opsporen, niet de geïmplementeerde code .

Om dit goed te maken, kunt u nu de boomstructuur de geschreven code laten weergeven. Hierdoor lijkt de boomstructuur meer op de bronbestanden die u in uw IDE te zien krijgt, en deze bestanden zijn nu gescheiden van de Deployed Code .

Schermafbeelding van de bestandsboom in Chrome DevTools met de geschreven code.

Om deze optie in Chrome DevTools in te schakelen, gaat u naar Instellingen > Experimenten en vinkt u Bronnen groeperen in geschreven en geïmplementeerde structuren aan.

Schermafbeelding van de instellingen van DevTools.

“Gewoon mijn code”

Wanneer u afhankelijkheden gebruikt of bovenop een raamwerk bouwt, kunnen bestanden van derden u in de weg zitten. Meestal wilt u alleen uw code zien, en niet die van een bibliotheek van derden die is weggestopt in de map node_modules .

Om dit goed te maken heeft DevTools standaard een extra instelling ingeschakeld: Voeg automatisch bekende scripts van derden toe aan de negeerlijst . Je kunt het vinden in DevTools > Instellingen > Negeerlijst .

Schermafbeelding van de instellingen van DevTools.

Als deze instelling is ingeschakeld, verbergt DevTools elk bestand of elke map die door een framework of build-tool is gemarkeerd om te negeren .

Vanaf Angular v14.1.0 is de inhoud van de node_modules en webpack mappen als zodanig gemarkeerd. Daarom verschijnen deze mappen, de bestanden daarin en andere artefacten van derden niet op verschillende plaatsen in DevTools.

Als auteur hoeft u niets te doen om dit nieuwe gedrag in te schakelen. Het is aan het raamwerk om deze verandering door te voeren.

Negeer code in stacktraces

Eén plaats waar deze op de negeerlijst staande bestanden niet langer verschijnen, is in stacktraces. Als auteur krijg je nu meer relevante stacktraces te zien.

Schermafbeelding van een stacktracering in DevTools.

Als u alle oproepframes van de stacktrace wilt zien, kunt u altijd op de link Meer frames weergeven klikken.

Hetzelfde geldt voor de call-stacks die u ziet tijdens het debuggen en het doorlopen van uw code . Wanneer frameworks of bundelaars DevTools informeren over scripts van derden, verbergt DevTools automatisch alle irrelevante oproepframes en springt over elke negeercode heen tijdens het stapsgewijs debuggen.

Schermafbeelding van de DevTools Sources Debugger tijdens het opsporen van fouten.

Negeer de code in de bestandsboom

Als u de bestanden en mappen op de negeerlijst wilt verbergen in de bestandsstructuur van de geschreven code in het paneel Bronnen , vinkt u Code op de negeerlijst verbergen in de bronstructuurweergave aan in Instellingen > Experimenten in DevTools.

Schermafbeelding van de instellingen van DevTools.

In het voorbeeldproject van Angular zijn de mappen node_modules en webpack nu verborgen.

Schermafbeelding van de bestandsstructuur in Chrome DevTools, waarbij de geschreven code wordt weergegeven, maar geen node_modules worden weergegeven.

Negeer de code in het menu "Snel openen".

Genegeerde code is niet alleen verborgen in de bestandsstructuur, maar is ook verborgen in het menu "Snel openen" ( Control + P (Linux/Windows) of Command + P (Mac) ).

Schermafbeelding van DevTools met het menu "Snel openen".

Meer verbeteringen om sporen te stapelen

Chrome DevTools heeft al relevante stacktraces besproken en introduceert nog meer verbeteringen voor stacktraces.

Gekoppelde stapelsporen

Wanneer sommige bewerkingen asynchroon moeten plaatsvinden, vertellen de stacktraces in DevTools momenteel slechts een deel van het verhaal.

Hier is bijvoorbeeld een heel eenvoudige planner in een hypothetisch framework.js bestand:

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

… en hoe een ontwikkelaar het in zijn eigen code zou kunnen gebruiken in een example.js bestand:

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

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

businessLogic();

Wanneer u een breekpunt toevoegt binnen de someTask -methode of wanneer u de trace inspecteert die in de console is afgedrukt, ziet u geen enkele vermelding van de businessLogic() aanroep die de “hoofdoorzaak” van deze bewerking was.

In plaats daarvan ziet u alleen de raamwerkplanningslogica die tot de taakuitvoering heeft geleid en geen broodkruimels in de stacktrace om u te helpen de causale verbanden te achterhalen tussen gebeurtenissen die tot deze taak hebben geleid.

Een stacktrace van asynchroon uitgevoerde code zonder informatie over wanneer deze was gepland.

Dankzij een nieuwe feature genaamd “Async Stack Tagging” is het mogelijk om toch het hele verhaal te vertellen door beide delen van de asynchrone code aan elkaar te koppelen.

De Async Stack Tagging API introduceert een nieuwe console met de naam console.createTask() . De API-handtekening is als volgt:

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

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

De aanroep console.createTask() retourneert een Task instantie die u later kunt gebruiken om de inhoud van de taak f uit te voeren.

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

// Task Execution
task.run(f);

De taak vormt de link tussen de context waarin deze is gemaakt en de context van de asynchrone functie die wordt uitgevoerd.

Toegepast op de makeScheduler functie van bovenaf, wordt de code als volgt:

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

Dankzij dit kan Chrome DevTools nu een betere stacktrace weergeven.

Een stacktrace van asynchroon uitgevoerde code met informatie over wanneer deze was gepland.

Merk op hoe businessLogic() nu is opgenomen in de stacktrace! Niet alleen dat, maar de taak heeft ook een bekende naam someTask in plaats van de algemene requestAnimationFrame zoals voorheen.

Vriendelijke oproepframes

Frameworks genereren bij het bouwen van een project vaak code uit allerlei sjabloontalen, zoals Angular- of JSX-sjablonen die HTML-achtige code omzetten in gewoon JavaScript dat uiteindelijk in de browser draait. Soms krijgen dit soort gegenereerde functies namen die niet erg vriendelijk zijn: namen met één letter nadat ze zijn verkleind, of obscure of onbekende namen, zelfs als dat niet het geval is.

In het voorbeeldproject is AppComponent_Template_app_button_handleClick_1_listener een voorbeeld hiervan, dat u ziet in de stacktracering.

Schermafbeelding van stacktrace met een automatisch gegenereerde functienaam.

Om dit aan te pakken ondersteunt Chrome DevTools nu het hernoemen van deze functies via bronkaarten. Als een brontoewijzing een naaminvoer heeft voor het begin van een functiebereik, moet het aanroepframe die naam weergeven in de stacktrace.

Als auteur hoeft u niets te doen om dit nieuwe gedrag in te schakelen. Het is aan het raamwerk om deze verandering door te voeren.

Vooruit kijken

Dankzij de toevoegingen die in dit bericht worden beschreven, kan Chrome DevTools u een betere foutopsporingservaring bieden. Er zijn meer gebieden die het team graag zou willen verkennen. In het bijzonder hoe u de profileringservaring in DevTools kunt verbeteren.

Het Chrome DevTools-team moedigt framework-auteurs aan om deze nieuwe mogelijkheden over te nemen. De Case Study: Better Angular Debugging with DevTools biedt richtlijnen voor de implementatie hiervan.