Modernes Web-Debugging in den Chrome-Entwicklertools

Einleitung

Heutzutage können Autoren ihre Webanwendungen anhand vieler Abstraktionen erstellen. Anstatt eine direkte Schnittstelle mit den untergeordneten APIs der Web-Plattform zu schaffen, nutzen viele Autoren Frameworks, entwickeln Tools und Compiler, um ihre Anwendungen aus einer höheren Ebene heraus zu schreiben.

Komponenten, die auf dem Angular-Framework aufbauen, werden beispielsweise in TypeScript mit HTML-Vorlagen erstellt. Im Hintergrund kompilieren Angular CLI und Webpack alles in JavaScript und kompilieren ein sogenanntes Bundle, das dann an den Browser gesendet wird.

Beim Debugging oder der Profilerstellung für Webanwendungen in den Entwicklertools können Sie derzeit diese kompilierte Version Ihres Codes anstelle des tatsächlich geschriebenen Codes sehen und debuggen. Als Autor sollten Sie jedoch Folgendes vermeiden:

  • Sie möchten keine Fehler in reduziertem JavaScript-Code beheben, sondern im ursprünglichen JavaScript-Code.
  • Wenn Sie TypeScript verwenden, möchten Sie keine JavaScript-Fehler beheben, sondern Ihren ursprünglichen TypeScript-Code.
  • Wenn Sie Vorlagen wie Angular, Lit oder JSX verwenden, möchten Sie nicht immer Fehler im resultierenden DOM beheben. Möglicherweise möchten Sie Fehler in den Komponenten selbst beheben.

Im Allgemeinen möchten Sie wahrscheinlich Ihren eigenen Code debuggen, während Sie ihn geschrieben haben.

Während Quellkarten diese Lücke bereits teilweise schließen, gibt es in diesem Bereich noch mehr Möglichkeiten für die Chrome-Entwicklertools und das System.

Sehen wir uns das genauer an!

Erstellt und bereitgestellter Code im Vergleich

Wenn Sie im Bereich „Quellen“ den Dateibaum aufrufen, sehen Sie derzeit den Inhalt des kompilierten und häufig reduzierten Bundles. Das sind die Dateien, die vom Browser heruntergeladen und ausgeführt werden. In den Entwicklertools heißt das Bereitgestellter Code.

Screenshot der Dateistruktur in den Chrome-Entwicklertools mit dem bereitgestellten Code

Das ist nicht sehr praktisch und oft schwer zu verstehen. Als Autor möchten Sie Ihren geschriebenen Code und nicht den bereitgestellten Code sehen und Fehler beheben.

Als Entschädigung können Sie jetzt festlegen, dass in der Baumstruktur stattdessen der Authored Code angezeigt wird. Dadurch ähnelt der Baum Quelldateien, die Sie in Ihrer IDE sehen, und diese Dateien sind jetzt vom bereitgestellten Code getrennt.

Screenshot der Dateistruktur in den Chrome-Entwicklertools mit dem erstellten Code

Um diese Option in den Chrome-Entwicklertools zu aktivieren, rufen Sie Einstellungen > Tests auf und klicken Sie auf das Kästchen neben Quellen in erstellte und bereitgestellte Bäume gruppieren.

Screenshot der Einstellungen der Entwicklertools.

„Nur mein Code“

Wenn Sie Abhängigkeiten verwenden oder auf einem Framework aufbauen, können Drittanbieterdateien im Weg stehen. Meistens soll nur der Code angezeigt werden und nicht der Code einer Drittanbieterbibliothek im Ordner node_modules.

Als Ausgleich dafür ist in den Entwicklertools standardmäßig eine zusätzliche Einstellung aktiviert: Bekannte Drittanbieter-Scripts automatisch der Ignorierliste hinzufügen. Sie finden sie unter DevTools > DevTools > DevTools.

Screenshot der Einstellungen der Entwicklertools.

Wenn diese Einstellung aktiviert ist, blendet die Entwicklertools alle Dateien und Ordner aus, die von einem Framework oder Build-Tool als zu ignorieren markiert wurden.

Ab Version 14.1.0 von Angular wurden die Inhalte der Ordner node_modules und webpack entsprechend gekennzeichnet. Daher werden diese Ordner, die darin enthaltenen Dateien und andere Artefakte von Drittanbietern nicht an verschiedenen Stellen in den Entwicklertools angezeigt.

Als Autor müssen Sie nichts weiter unternehmen, um dieses neue Verhalten zu aktivieren. Es liegt an dem Framework, diese Änderung umzusetzen.

Code auf Ignorieren in Stacktraces

Dateien auf der Ignorieren-Liste werden nur noch in den Stacktraces angezeigt. Als Autor sehen Sie jetzt mehr relevante Stacktraces.

Screenshot eines Stacktrace in den Entwicklertools.

Wenn Sie alle Aufruf-Frames des Stacktrace sehen möchten, können Sie jederzeit auf den Link Weitere Frames anzeigen klicken.

Dasselbe gilt für die Aufrufstacks, die Sie beim Debuggen und Durchgehen des Codes sehen. Wenn die Entwicklertools von Frameworks oder Bundlern über Scripts von Drittanbietern informiert werden, blenden die Entwicklertools automatisch alle nicht relevanten Aufrufframes aus und springen beim schrittweisen Debuggen über Code auf der Ignorierliste.

Screenshot des Entwicklertools-Quellen-Debuggers während der Fehlerbehebung.

Code auf Ignorieren in der Dateistruktur

Wenn Sie die Dateien und Ordner auf der Ignorieren-Liste in der Dateistruktur Authored Code im Bereich Quellen ausblenden möchten, aktivieren Sie in den Entwicklertools unter Einstellungen > Tests das Kontrollkästchen Code auf der Ignorieren-Liste in der Baumansicht der Quellen ausblenden.

Screenshot der Einstellungen der Entwicklertools.

Im Angular-Beispielprojekt sind die Ordner node_modules und webpack jetzt ausgeblendet.

Screenshot der Dateistruktur in den Chrome-Entwicklertools mit dem Authored Code, aber ohne node_modules.

Code auf der Ignorieren-Liste im Menü „Schnell öffnen“

Ignorierter Code wird nicht nur in der Dateistruktur ausgeblendet, sondern auch im Menü „Schnell öffnen“ (Strg + P (Linux/Windows) oder Befehlstaste + P (Mac)).

Screenshot der Entwicklertools mit dem Menü „Schnell öffnen“.

Weitere Verbesserungen bei Stacktraces

Nachdem die relevanten Stacktraces bereits behandelt wurden, bieten die Chrome-Entwicklertools noch weitere Verbesserungen an den Stacktraces.

Verknüpfte Stacktraces

Wenn einige Vorgänge asynchron geplant sind, erzählen die Stacktraces in den Entwicklertools derzeit nur einen Teil der Geschichte.

Hier sehen Sie beispielsweise einen sehr einfachen Planer in einer hypothetischen Datei framework.js:

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

...und wie ein Entwickler sie in seinem eigenen Code in einer example.js-Datei verwenden könnte:

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

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

businessLogic();

Wenn Sie in der Methode someTask einen Haltepunkt hinzufügen oder den in der Konsole gedruckten Trace untersuchen, wird der businessLogic()-Aufruf, der die Ursache dieses Vorgangs war, nicht erwähnt.

Stattdessen sehen Sie nur die Framework-Planungslogik, die zur Ausführung der Aufgabe geführt hat, und keine Breadcrumbs im Stacktrace, um die kausalen Verbindungen zwischen Ereignissen zu ermitteln, die zu dieser Aufgabe führen.

Ein Stacktrace von asynchronem ausgeführtem Code ohne Informationen zum Zeitpunkt der Planung.

Dank der neuen Funktion „Async Stack Tagging“ kann man schließlich die ganze Geschichte erzählen, indem beide Teile des asynchronen Codes miteinander verknüpft werden.

Mit der Async Stack Tagging API wird eine neue console-Methode namens console.createTask() eingeführt. Die API-Signatur lautet wie folgt:

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

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

Der console.createTask()-Aufruf gibt eine Task-Instanz zurück, die Sie später verwenden können, um den Inhalt der Aufgabe f auszuführen.

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

// Task Execution
task.run(f);

Die Aufgabe bildet die Verknüpfung zwischen dem Kontext, in dem sie erstellt wurde, und dem Kontext der asynchronen Funktion, die ausgeführt wird.

Wenn Sie auf die obige Funktion makeScheduler angewendet werden, sieht der Code so aus:

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

Dank dieser Informationen können die Chrome-Entwicklertools jetzt einen besseren Stacktrace anzeigen.

Ein Stacktrace von asynchronem ausgeführtem Code mit Informationen darüber, wann er geplant wurde.

Beachten Sie, dass businessLogic() jetzt im Stacktrace enthalten ist. Außerdem hat die Aufgabe einen bekannten Namen someTask anstelle des generischen requestAnimationFrame wie zuvor.

Angepasste Anruf-Frames

Frameworks generieren beim Erstellen eines Projekts oft Code aus allen Arten von Vorlagensprachen. Dazu gehören beispielsweise Angular- oder JSX-Vorlagen, die HTML-ähnlichen Code in einfachen JavaScript-Code umwandeln, der schließlich im Browser ausgeführt wird. Manchmal erhalten solche generierten Funktionen Namen, die nicht besonders freundlich sind – entweder Namen aus einzelnen Buchstaben, nachdem sie reduziert wurden, oder unbekannte oder unbekannte Namen, auch wenn dies nicht der Fall ist.

Im Beispielprojekt ist ein Beispiel dafür AppComponent_Template_app_button_handleClick_1_listener, das Sie im Stacktrace sehen.

Screenshot des Stacktrace mit einem automatisch generierten Funktionsnamen

Aus diesem Grund unterstützen die Chrome-Entwicklertools jetzt das Umbenennen dieser Funktionen über Source Maps. Wenn eine Quellzuordnung einen Namenseintrag für den Beginn eines Funktionsbereichs enthält, sollte der Aufruf-Frame diesen Namen im Stacktrace anzeigen.

Als Autor müssen Sie nichts weiter unternehmen, um dieses neue Verhalten zu aktivieren. Es liegt an dem Framework, diese Änderung umzusetzen.

Zukunftspläne

Dank der Ergänzungen, die in diesem Beitrag beschrieben wurden, können die Chrome-Entwicklertools Ihnen eine bessere Fehlerbehebung bieten. Es gibt weitere Bereiche, die das Team gerne erkunden möchte. Insbesondere geht es darum, wie die Profilerstellung in den Entwicklertools verbessert werden kann.

Das Chrome-Entwicklertools-Team ermutigt Framework-Autoren dazu, diese neuen Funktionen zu übernehmen. In der Fallstudie: Better Angular Debugging with DevTools wird erklärt, wie dies umgesetzt werden kann.