Studi Kasus: Proses Debug Angular yang Lebih Baik dengan DevTools

Pengalaman proses debug yang lebih baik

Selama beberapa bulan terakhir, tim Chrome DevTools berkolaborasi dengan tim Angular untuk meluncurkan peningkatan pada pengalaman proses debug di Chrome DevTools. Orang-orang dari kedua tim bekerja sama dan mengambil langkah untuk memungkinkan developer melakukan debug dan membuat profil aplikasi web dari perspektif pembuatan: dalam hal bahasa sumber dan struktur project mereka, dengan akses ke informasi yang tidak asing dan relevan bagi mereka.

Postingan ini membahas di balik layar untuk melihat perubahan mana dalam Angular dan Chrome DevTools yang diperlukan untuk mencapai hal ini. Meskipun beberapa perubahan ini ditunjukkan melalui Angular, perubahan tersebut juga dapat diterapkan ke framework lain. Tim Chrome DevTools mendorong framework lain untuk mengadopsi API konsol baru dan titik ekstensi peta sumber sehingga mereka juga bisa menawarkan pengalaman proses debug yang lebih baik kepada pengguna.

Kode listingan diabaikan

Saat men-debug aplikasi menggunakan Chrome DevTools, penulis umumnya hanya ingin melihat kodenya saja, bukan kode framework di bawahnya atau beberapa dependensi yang disembunyikan di folder node_modules.

Untuk mencapai hal ini, tim DevTools telah memperkenalkan ekstensi untuk peta sumber, yang disebut x_google_ignoreList. Ekstensi ini digunakan untuk mengidentifikasi sumber pihak ketiga, seperti kode framework atau kode yang dihasilkan pemaket. Saat framework menggunakan ekstensi ini, penulis kini otomatis menghindari kode yang tidak ingin dilihat atau dilangkah tanpa harus mengonfigurasinya secara manual sebelumnya.

Dalam praktiknya, Chrome DevTools bisa secara otomatis menyembunyikan kode yang diidentifikasi seperti itu di stack trace, hierarki Sources, dialog Quick Open, dan juga meningkatkan perilaku melangkah dan melanjutkan di debugger.

GIF animasi yang menampilkan DevTools sebelum dan sesudahnya. Perhatikan bahwa setelah gambar, DevTools menampilkan Authored Code di hierarki, tidak lagi menyarankan file framework di menu “Quick Open”, dan menunjukkan stack trace yang jauh lebih bersih di sebelah kanan.

Ekstensi peta sumber x_google_ignoreList

Di peta sumber, kolom x_google_ignoreList baru mengacu pada array sources, dan mencantumkan indeks semua sumber pihak ketiga yang diketahui dalam peta sumber tersebut. Saat mengurai peta sumber, Chrome DevTools akan menggunakan ini untuk mencari tahu bagian kode mana yang harus diabaikan.

Berikut adalah peta sumber untuk file yang dihasilkan out.js. Ada dua sources asli yang berkontribusi untuk menghasilkan file output: foo.js dan lib.js. Yang pertama adalah sesuatu yang ditulis oleh pengembang situs web dan yang terakhir adalah kerangka kerja yang mereka gunakan.

{
  "version" : 3,
  "file": "out.js",
  "sourceRoot": "",
  "sources": ["foo.js", "lib.js"],
  "sourcesContent": ["...", "..."],
  "names": ["src", "maps", "are", "fun"],
  "mappings": "A,AAAB;;ABCDE;"
}

sourcesContent disertakan untuk kedua sumber asli ini dan Chrome DevTools akan menampilkan file ini secara default di seluruh Debugger:

  • Sebagai file di hierarki Sumber.
  • Sebagai hasil dalam dialog Quick Open.
  • Sebagai lokasi frame panggilan yang dipetakan dalam stack trace error saat dijeda pada titik henti sementara dan saat melangkah.

Ada satu informasi tambahan yang kini dapat disertakan dalam peta sumber untuk mengidentifikasi sumber mana yang merupakan kode pihak pertama atau ketiga:

{
  ...
  "sources": ["foo.js", "lib.js"],
  "x_google_ignoreList": [1],
  ...
}

Kolom x_google_ignoreList baru berisi satu indeks yang merujuk ke array sources: 1. Hal ini menentukan bahwa wilayah yang dipetakan ke lib.js sebenarnya adalah kode pihak ketiga yang harus otomatis ditambahkan ke daftar yang diabaikan.

Dalam contoh yang lebih kompleks, yang ditunjukkan di bawah, indeks 2, 4, dan 5 menentukan bahwa wilayah yang dipetakan ke lib1.ts, lib2.coffee, dan hmr.js adalah kode pihak ketiga yang akan otomatis ditambahkan ke daftar yang diabaikan.

{
  ...
  "sources": ["foo.html", "bar.css", "lib1.ts", "baz.js", "lib2.coffee", "hmr.js"],
  "x_google_ignoreList": [2, 4, 5],
  ...
}

Jika Anda adalah developer framework atau pemaket, pastikan peta sumber yang dihasilkan selama proses build menyertakan kolom ini untuk terhubung ke kemampuan baru ini di Chrome DevTools.

x_google_ignoreList dalam Angular

Mulai Angular v14.1.0, konten folder node_modules dan webpack telah ditandai sebagai “untuk diabaikan”.

Hal ini dicapai melalui perubahan pada angular-cli dengan membuat plugin yang terhubung ke modul Compiler webpack

Plugin webpack yang dibuat hook oleh engineer kami ke dalam tahap PROCESS_ASSETS_STAGE_DEV_TOOLING dan mengisi kolom x_google_ignoreList di peta sumber untuk aset akhir yang dihasilkan webpack dan yang dimuat browser.

const map = JSON.parse(mapContent) as SourceMap;
const ignoreList = [];

for (const [index, path] of map.sources.entries()) {
  if (path.includes('/node_modules/') || path.startsWith('webpack/')) {
    ignoreList.push(index);
  }
}

map[`x_google_ignoreList`] = ignoreList;
compilation.updateAsset(name, new RawSource(JSON.stringify(map)));

Stack trace tertaut

Stack trace menjawab pertanyaan tentang “bagaimana saya bisa sampai di sini”, tetapi sering kali hal ini berasal dari perspektif komputer, dan belum tentu sesuatu yang sesuai dengan perspektif developer atau model mental mereka dari runtime aplikasi. Hal ini terutama berlaku ketika beberapa operasi dijadwalkan untuk terjadi secara asinkron nanti: mungkin masih menarik untuk mengetahui "akar penyebab" atau sisi penjadwalan operasi tersebut, tetapi hal tersebut tidak akan menjadi bagian dari pelacakan tumpukan asinkron.

V8 secara internal memiliki mekanisme untuk melacak tugas asinkron tersebut ketika primitif penjadwalan browser standar digunakan, seperti setTimeout. Hal ini dilakukan secara default dalam kasus tersebut, sehingga developer sudah dapat memeriksanya. Namun pada project yang lebih kompleks, hal ini tidak sesederhana itu, terutama saat menggunakan framework dengan mekanisme penjadwalan yang lebih canggih—misalnya, framework yang melakukan pelacakan zona, pengantrean tugas khusus, atau yang membagi update menjadi beberapa unit pekerjaan yang dijalankan seiring waktu.

Untuk mengatasinya, DevTools mengekspos mekanisme yang disebut “Async Stack Tagging API” pada objek console, yang memungkinkan developer framework memberi petunjuk baik lokasi tempat operasi dijadwalkan serta tempat operasi dijalankan.

Asynchronous Stack Tagging API

Tanpa Pemberian Tag Stack Asinkron, pelacakan tumpukan untuk kode yang dijalankan secara asinkron oleh framework akan muncul tanpa koneksi ke kode tempat kode tersebut dijadwalkan.

Stack trace dari beberapa kode yang dieksekusi secara asinkron tanpa informasi tentang waktu penjadwalannya. Fungsi ini hanya menampilkan stack trace yang dimulai dari `requestAnimationFrame`, tetapi tidak menyimpan informasi sejak dijadwalkan.

Dengan Pemberian Tag Tumpukan Asinkron, Anda dapat memberikan konteks ini, dan pelacakan tumpukan akan terlihat seperti ini:

Stack trace dari beberapa kode yang dieksekusi secara asinkron dengan informasi tentang waktu penjadwalannya. Tidak seperti sebelumnya, perhatikan bagaimana alat ini menyertakan `businessLogic` dan `schedule` dalam stack trace.

Untuk melakukannya, gunakan metode console baru bernama console.createTask() yang disediakan oleh Async Stack Tagging API. Tanda tangannya adalah sebagai berikut:

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

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

Memanggil console.createTask() akan menampilkan instance Task yang nanti dapat Anda gunakan untuk menjalankan kode asinkron.

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

// Task Execution
task.run(f);

Operasi asinkron juga dapat disusun bertingkat, dan "penyebab utama" akan ditampilkan dalam pelacakan tumpukan secara berurutan.

Tugas dapat dijalankan berapa kali pun dan payload pekerjaan dapat berbeda di setiap operasi. Stack panggilan di situs penjadwalan akan diingat sampai objek tugas dibersihkan.

API Pemberian Tag Stack Asinkron di Angular

Di Angular, perubahan telah dilakukan pada NgZone – konteks eksekusi Angular yang tetap ada di seluruh tugas asinkron.

Saat menjadwalkan tugas, tugas menggunakan console.createTask() jika tersedia. Instance Task yang dihasilkan disimpan untuk digunakan lebih lanjut. Setelah memanggil tugas, NgZone akan menggunakan instance Task yang tersimpan untuk menjalankannya.

Perubahan ini diterapkan di NgZone 0.11.8 Angular melalui permintaan pull #46693 dan #46958.

Frame Panggilan yang Ramah

Framework sering kali menghasilkan kode dari semua jenis bahasa template saat membuat project, seperti template Angular atau JSX yang mengubah kode yang tampak HTML menjadi JavaScript biasa yang akhirnya berjalan di browser. Terkadang, fungsi yang dihasilkan jenis ini diberi nama yang tidak terlalu mirip — baik nama dengan huruf tunggal setelah diminifikasi atau nama yang tidak jelas atau asing bahkan jika tidak.

Di Angular, tidak jarang melihat frame panggilan dengan nama seperti AppComponent_Template_app_button_handleClick_1_listener dalam pelacakan tumpukan.

Screenshot stack trace dengan nama fungsi yang dibuat secara otomatis.

Untuk mengatasi hal ini, Chrome DevTools kini mendukung penggantian nama fungsi ini melalui peta sumber. Jika source map memiliki entri nama untuk awal cakupan fungsi (yaitu, kurung siku kiri daftar parameter), frame panggilan harus menampilkan nama tersebut dalam stack trace.

Frame Panggilan yang Ramah dalam Angular

Mengganti nama frame panggilan di Angular merupakan upaya berkelanjutan. Kami berharap peningkatan ini tersedia secara bertahap seiring waktu.

Saat mengurai template HTML yang telah ditulis penulis, compiler Angular menghasilkan kode TypeScript, yang akhirnya ditranspilasi menjadi kode JavaScript yang dimuat dan dijalankan oleh browser.

Sebagai bagian dari proses pembuatan kode ini, peta sumber juga dibuat. Saat ini kami sedang mengeksplorasi cara-cara untuk memasukkan nama fungsi di bidang "nama" peta sumber, dan merujuk nama-nama tersebut dalam pemetaan antara kode yang dihasilkan dan kode asli.

Misalnya, jika fungsi untuk pemroses peristiwa dibuat dan namanya tidak sesuai atau dihapus selama minifikasi, peta sumber kini dapat menyertakan nama yang lebih sesuai untuk fungsi ini di kolom "names" dan pemetaan untuk awal cakupan fungsi kini dapat merujuk ke nama ini (yaitu, paren kiri daftar parameter). Chrome DevTools kemudian akan menggunakan nama-nama ini untuk mengganti nama frame panggilan dalam pelacakan tumpukan.

Rencana ke depan

Menggunakan Angular sebagai uji coba untuk memverifikasi bahwa pekerjaan kami telah menjadi pengalaman yang luar biasa. Kami ingin mendengar pendapat developer framework dan memberikan masukan kepada kami terkait poin-poin tambahan ini.

Ada lebih banyak area yang ingin kita jelajahi. Khususnya, cara meningkatkan pengalaman pembuatan profil di DevTools.