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 men-debug dan membuat profil aplikasi web dari perspektif pembuatan: dalam hal bahasa sumber dan struktur project mereka, dengan akses ke informasi yang familier dan relevan bagi mereka.

Postingan ini membahas di balik layar untuk melihat perubahan mana di 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 yang baru dan titik ekstensi peta sumber sehingga mereka juga dapat menawarkan pengalaman proses debug yang lebih baik kepada pengguna.

Kode listingan abaikan

Saat men-debug aplikasi menggunakan Chrome DevTools, penulis umumnya hanya ingin melihat kode mereka saja, bukan kode framework yang ada di bawahnya atau beberapa dependensi yang tersembunyi dalam 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 dibuat pemaket. Jika framework menggunakan ekstensi ini, penulis kini akan otomatis menghindari kode yang tidak ingin dilihat atau dijelajahi tanpa harus mengonfigurasinya secara manual sebelumnya.

Dalam praktiknya, Chrome DevTools bisa otomatis menyembunyikan kode yang teridentifikasi seperti dalam pelacakan tumpukan, pohon Sumber, dialog Quick Open, dan juga meningkatkan perilaku stepping dan melanjutkan di debugger.

GIF animasi yang menampilkan DevTools sebelum dan sesudah. Perhatikan bagaimana di gambar berikutnya, DevTools menampilkan Authored Code di hierarki, tidak lagi menyarankan file framework di menu "Quick Open", dan menampilkan pelacakan tumpukan yang jauh lebih rapi di sebelah kanan.

Ekstensi peta sumber x_google_ignoreList

Dalam 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 menggunakannya untuk mencari tahu bagian kode mana yang harus dicantumkan dalam daftar yang diabaikan.

Di bawah ini adalah peta sumber untuk file out.js yang dihasilkan. Ada dua sources asli yang berkontribusi dalam menghasilkan file output: foo.js dan lib.js. Yang pertama adalah sesuatu yang ditulis oleh pengembang situs web dan yang kedua 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 dalam 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. Kolom 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 ditampilkan 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 harus 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 bundler, pastikan peta sumber yang dihasilkan selama proses build menyertakan kolom ini untuk terhubung ke kemampuan baru ini di Chrome DevTools.

x_google_ignoreList di Angular

Mulai Angular v14.1.0, isi folder node_modules dan webpack telah ditandai sebagai “toIgnore”.

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

Plugin webpack yang dibuat oleh engineer kami sebagai hook ke dalam tahap PROCESS_ASSETS_STAGE_DEV_TOOLING dan mengisi kolom x_google_ignoreList di peta sumber untuk aset akhir yang dihasilkan webpack dan dimuat oleh 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)));

Pelacakan tumpukan yang ditautkan

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

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

Untuk mengatasinya, DevTools menampilkan mekanisme yang disebut "Async Stack Tagging API" pada objek console, yang memungkinkan developer framework menunjukkan lokasi tempat operasi dijadwalkan serta tempat operasi ini dijalankan.

Async Stack Tagging API

Tanpa Pemberian Tag Tumpukan Asinkron, pelacakan tumpukan untuk kode yang dieksekusi secara asinkron dengan cara yang kompleks 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 penjadwalan. Kode ini hanya menampilkan pelacakan tumpukan yang dimulai dari `requestAnimationFrame` tetapi tidak menyimpan informasi sejak jadwal 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 penjadwalan. Tidak seperti sebelumnya, perhatikan bahwa hal ini menyertakan `businessLogic` dan `schedule` di stack trace.

Untuk melakukannya, gunakan metode console baru bernama console.createTask() yang disediakan oleh Async Stack Tagging API. Berikut tanda tangannya:

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

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

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

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

// Task Execution
task.run(f);

Operasi asinkron juga bisa disarangkan, dan “akar penyebab” akan ditampilkan di pelacakan tumpukan secara berurutan.

Tugas dapat dijalankan beberapa kali dan payload pekerjaan dapat berbeda setiap kali dijalankan. Stack panggilan di situs penjadwalan akan diingat sampai objek tugas dibersihkan sebagai sampah.

Async Stack Tagging API di Angular

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

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

Perubahan ini mendarat 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 terlihat dalam HTML menjadi JavaScript biasa yang pada akhirnya berjalan di browser. Kadang-kadang, jenis fungsi yang dihasilkan ini diberi nama yang tidak terlalu ramah — baik nama huruf tunggal setelah diminifikasi atau nama yang tidak jelas atau asing bahkan ketika mereka sebenarnya tidak.

Di Angular, biasanya frame panggilan dengan nama seperti AppComponent_Template_app_button_handleClick_1_listener dalam stack trace ditampilkan.

Screenshot stack trace dengan nama fungsi yang dibuat secara otomatis.

Untuk mengatasinya, Chrome DevTools kini mendukung penggantian nama fungsi-fungsi ini melalui peta sumber. Jika peta sumber memiliki entri nama untuk awal cakupan fungsi (yaitu, paren kiri daftar parameter), frame panggilan harus menampilkan nama tersebut di stack trace.

Frame Panggilan yang Ramah di Angular

Mengganti nama frame panggilan di Angular adalah upaya berkelanjutan. Kami berharap peningkatan ini dapat diterapkan secara bertahap dari waktu ke waktu.

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

Sebagai bagian dari proses pembuatan kode ini, peta sumber juga dibuat. Saat ini kami sedang mempelajari cara untuk menyertakan nama fungsi di kolom "names" pada peta sumber, dan mereferensikan nama tersebut dalam pemetaan antara kode yang dihasilkan dan kode asli.

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

Rencana ke depan

Menggunakan Angular sebagai uji coba uji coba untuk memverifikasi pekerjaan kami merupakan pengalaman yang luar biasa. Kami ingin mendengar pendapat dari developer framework dan memberikan masukan terkait poin-poin ekstensi ini.

Ada area lain yang ingin kami jelajahi. Khususnya, cara meningkatkan pengalaman pembuatan profil di DevTools.