Nowoczesne debugowanie stron internetowych w Narzędziach deweloperskich w Chrome

Wprowadzenie

Obecnie autorzy mogą korzystać z wielu abstrakcji do tworzenia aplikacji internetowych. Zamiast bezpośrednio komunikować się z interfejsami API niższego poziomu, które są dostępne w ramach platformy internetowej, wielu autorów posługuje się platformami, narzędziami do kompilacji i kompilatorami, aby pisać swoje aplikacje z perspektywy wyższego poziomu.

Na przykład komponenty tworzone na podstawie platformy Angular są tworzone w TypeScript za pomocą szablonów HTML. W tle interfejs wiersza poleceń Angulara i webpack kompilują wszystko do JavaScriptu i do tak zwanego pakietu, który jest następnie wysyłany do przeglądarki.

Podczas debugowania lub profilowania aplikacji internetowych w DevTools możesz obecnie wyświetlać i debugować skompilowaną wersję kodu zamiast kodu, który został faktycznie napisany. Jako autor nie chcesz jednak, aby tak się stało:

  • Nie chcesz debugować zminifikowanego kodu JavaScript, tylko oryginalny kod JavaScript.
  • Jeśli używasz TypeScriptu, nie chcesz debugować JavaScriptu, tylko debugować oryginalny kod TypeScript.
  • Gdy używasz szablonów, np. Angular, Lit lub JSX, nie zawsze chcesz debugować wynikowy DOM. Możesz debugować same komponenty.

Ogólnie rzecz biorąc, wolisz debugować własny kod w czasie, gdy go napisał.

Mapy źródeł już w pewnym stopniu wypełniają tę lukę, ale Narzędzia deweloperskie w Chrome i ekosystem mogą jeszcze więcej w tej dziedzinie.

Przyjrzyjmy się im bliżej.

Kod autorski a kod wdrożony

Obecnie podczas poruszania się po drzewie plików w panelu źródeł możesz zobaczyć zawartość skompilowanego i często zminiaturyzowanego pakietu. To są rzeczywiste pliki, które przeglądarka pobiera i uruchamia. W Narzędziach deweloperskich jest to wdrożony kod.

Zrzut ekranu przedstawiający drzewo plików w Narzędziach deweloperskich w Chrome, w którym widać wdrożoną funkcję.

Nie jest to wygodne i często trudne do zrozumienia. Jako autor chcesz wyświetlić i przeprowadzić debugowanie kodu, który napisałeś, a nie wdrożonego kodu.

Aby to zrekompensować, możesz teraz wyświetlić w drzewie kod autorski. Dzięki temu drzewo będzie bardziej przypominać pliki źródłowe widoczne w IDE, a pliki te będą teraz oddzielone od wdrożonego kodu.

Zrzut ekranu przedstawiający drzewo plików w Narzędziach deweloperskich w Chrome, w którym widoczny jest kod autoryzowany.

Aby włączyć tę opcję w Narzędziach deweloperskich Chrome, kliknij Ustawienia > Eksperymenty i zaznacz pole wyboru Grupuj źródła w drzewa Autoryzowane i Wdrożone.

Zrzut ekranu ustawień Narzędzi deweloperskich

„Tylko mój kod”

Podczas korzystania z zależności lub tworzenia na podstawie frameworku mogą Ci przeszkadzać pliki innych firm. Zwykle chcesz widzieć tylko swój kod, a nie bibliotekę innej firmy, która znajduje się w folderze node_modules.

Aby to zrekompensować, w Narzędziach deweloperskich jest domyślnie włączone dodatkowe ustawienie: Automatycznie dodawaj znane skrypty innych firm do listy ignorowanych. Znajdziesz go w sekcji Narzędzia dla programistów > Ustawienia > Lista ignorowania.

Zrzut ekranu ustawień Narzędzi deweloperskich

Gdy to ustawienie jest włączone, DevTools ukrywa wszystkie pliki i foldery, które zostały oznaczone przez framework lub narzędzie do kompilacji jako do zignorowania.

Od wersji Angular 14.1.0 zawartość folderów node_moduleswebpack została oznaczona jako taka. Dlatego te foldery, pliki w nich i inne tego typu elementy zewnętrzne nie pojawiają się w różnych miejscach w DevTools.

Jako autor nie musisz nic robić, aby włączyć tę nową funkcję. Wdrożenie tej zmiany zależy od platformy.

.

Kod z listy ignorowanych w wyświetleniach stosu

Te ignorowane pliki nie są już widoczne w zrzutach stosu. Jako autor masz teraz dostęp do bardziej przydatnych zrzutów stosu.

Zrzut ekranu przedstawiający ślad stosu w Narzędziach dla programistów

Jeśli chcesz zobaczyć wszystkie ramki wywołania w wyświetleniu stosu, możesz kliknąć link Pokaż więcej ramek.

To samo dotyczy stert wywołań, które widzisz podczas debugowania i przechodzenia przez kod. Gdy frameworki lub pakietatory informują Narzędzia deweloperskie o skryptach innych firm, Narzędzia deweloperskie automatycznie ukrywają wszystkie nieistotne ramki wywołania i podczas debugowania krok po kroku pomijają kod z listy ignorowanych.

Zrzut ekranu pokazujący debugera źródeł w Narzędziach deweloperskich podczas debugowania.

Kod z ignorowanego kodu w drzewie plików

Aby ukryć pliki i foldery z listy ignorowanych z drzewa plików Kod autora w panelu Źródła, zaznacz Ukryj ignorowany kod w widoku drzewa źródeł w sekcji Ustawienia > Eksperymenty w DevTools.

Zrzut ekranu ustawień Narzędzi deweloperskich

W tym przykładowym projekcie Angulara foldery node_moduleswebpack są teraz ukryte.

Zrzut ekranu przedstawiający drzewo plików w Narzędziach deweloperskich w Chrome, w którym widoczny jest kod autorski, ale nie node_modules

Kod na liście ignorowanych w menu „Otwórz szybko”

Kod z listy ignorowanych nie tylko nie jest widoczny w drzewie plików, ale też nie jest widoczny w menu „Otwórz szybko” (Control + P (Linux/Windows) lub Command + P (Mac)).

Zrzut ekranu przedstawiający Narzędzia dla programistów z menu „Szybkie otwieranie”.

Kolejne ulepszenia zrzutów stosu

Po omówieniu istotnych zrzutów stosu w Narzędziach deweloperskich Chrome wprowadzamy jeszcze więcej ulepszeń zrzutów stosu.

Zrzuty stosu połączonych

Gdy niektóre operacje są zaplanowane do wykonania asynchronicznie, ścieżki stosu w DevTools pokazują tylko część informacji.

Oto na przykład bardzo prosty harmonogram w hipotetycznym pliku 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();

…i jak deweloper może go używać we własnym kodzie w pliku example.js:

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

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

businessLogic();

Po dodaniu punktu przerwania w metodie someTask lub podczas sprawdzania śladu wydrukowanego w konsoli nie widzisz żadnej wzmianki o wywołaniu funkcji businessLogic(), która była „przyczyną pierwotną” tej operacji.

Zamiast tego w śladzie pakietu widzisz tylko logikę planowania, która doprowadziła do wykonania zadania. Nie ma w nim jednak informacji o powiązaniach przyczynowo-skutkowych między zdarzeniami prowadzącymi do tego zadania.

ślad stosu dla niektórych asynchronicznie wykonywanych fragmentów kodu bez informacji o tym, kiedy zostały zaplanowane;

Dzięki nowej funkcji o nazwie „Asynchroniczne tagowanie stosu” można przecież opowiedzieć wszystko na ten temat dzięki połączeniu ze sobą obu części kodu asynchronicznego.

Interfejs API otagowania asynkronicznej grupy wprowadza nową metodę console o nazwie console.createTask(). Podpis API ma postać:

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

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

Wywołanie console.createTask() zwraca instancję Task, której można później użyć do uruchomienia zawartości zadania f.

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

// Task Execution
task.run(f);

Zadaniem jest połączenie kontekstu, w którym zostało utworzone, z kontekstem wykonywanej funkcji asynchronicznej.

Zastosowany do powyższej funkcji makeScheduler kod wygląda tak:

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

Dzięki temu Narzędzia deweloperskie w Chrome mogą teraz lepiej prezentować zrzut stosu.

ślad stosu z niektórego asynchronicznie wykonanego kodu z informacjami o jego zaplanowaniu.

Zwróć uwagę, że businessLogic() jest teraz uwzględniona w wyświetleniu ścieżki wywołania. Nie tylko to, ale zadanie ma znajomą nazwę someTask zamiast ogólnego requestAnimationFrame jak wcześniej.

Przyjazne ramki wywołania

Podczas tworzenia projektu frameworki często generują kod z różnych języków szablonów, takich jak Angular czy szablony JSX, które przekształcają kod podobny do kodu HTML w zwykły kod JavaScript, który ostatecznie działa w przeglądarce. Czasami tego typu wygenerowane funkcje mają nazwy, które nie są zbyt przyjazne – albo nazwy jednoliterowe po ich zminimalizowaniu, albo niejasne lub nieznane nazwy, nawet jeśli nie są one zminimalizowane.

W przykładowym projekcie jest to funkcja AppComponent_Template_app_button_handleClick_1_listener, która pojawia się w zrzucie stosu.

Zrzut ekranu ścieżki wywołania z automatycznie wygenerowaną nazwą funkcji

Aby rozwiązać ten problem, w Narzędziach deweloperskich w Chrome możesz teraz zmieniać nazwy tych funkcji za pomocą map źródłowych. Jeśli mapa źródłowa ma wpis z nazwą początku zakresu funkcji, ramka wywołania powinna wyświetlić tę nazwę w zrzucie stosu.

Jako autor nie musisz nic robić, aby włączyć tę nową funkcję. Implementacja tej zmiany zależy od platformy.

Perspektywy

Dzięki dodatkom omówionym w tym poście możesz zwiększyć komfort debugowania w Narzędziach deweloperskich w Chrome. Zespół chce zbadać jeszcze inne obszary. W szczególności chodzi o to, jak ulepszyć profilowanie w Narzędziach deweloperskich.

Zespół Chrome DevTools zachęca autorów frameworków do korzystania z tych nowych funkcji. W studium przypadku: ulepszone debugowanie Angulara za pomocą Narzędzi dla deweloperów znajdziesz wskazówki dotyczące implementacji.