Örnek Olay: Geliştirici Araçları ile Daha İyi Angular Hata Ayıklama

Daha iyi bir hata ayıklama deneyimi

Geçtiğimiz birkaç ay boyunca Chrome Geliştirici Araçları ekibi, Chrome Geliştirici Araçları'ndaki hata ayıklama deneyiminde iyileştirmeler yapmak için Angular ekibiyle işbirliği yaptı. Her iki ekipten de kişiler birlikte çalıştı ve geliştiricilerin yazım açısından web uygulamalarında hata ayıklaması ve profil çıkarması için gerekli adımları attı.

Bu yayında, bunu sağlamak için Angular ve Chrome Geliştirici Araçları'nda hangi değişikliklerin yapılması gerektiğini anlamak üzere arka plan ayrıntılarına göz atılıyor. Bu değişikliklerin bazıları Angular üzerinden gösterilse de diğer çerçevelere de uygulanabilir. Chrome Geliştirici Araçları ekibi, kullanıcılarına daha iyi bir hata ayıklama deneyimi sunabilmeleri için diğer çerçeveleri de yeni konsol API'lerini ve kaynak harita uzantısı noktalarını kullanmaya teşvik eder.

Kodları yoksayın

Chrome Geliştirici Araçları'nı kullanarak uygulamalarda hata ayıklarken, yazarlar genellikle yalnızca sadece kendi kodlarını görmek isterler, altındaki çerçeveyi veya node_modules klasöründe gizlenmiş bir bağımlılığı görmek istemezler.

Bunun için Geliştirici Araçları ekibi, kaynak haritaları adlı, x_google_ignoreList adlı bir uzantıyı kullanıma sundu. Bu uzantı, çerçeve kodu veya paketleyici tarafından oluşturulan kod gibi üçüncü taraf kaynakları tanımlamak için kullanılır. Bir çerçeve bu uzantıyı kullandığında, yazarlar artık önceden manuel olarak yapılandırmak zorunda kalmadan görmek istemedikleri kodları otomatik olarak kullanmaktan kaçınır veya adım adım ilerler.

Pratikte, Chrome Geliştirici Araçları; yığın izlemelerde, Kaynaklar ağacında, Hızlı Aç iletişim kutusunda olduğu gibi tanımlanan kodları otomatik olarak gizleyebilir ve hata ayıklayıcıdaki adım oluşturma ve devam ettirme davranışını iyileştirebilir.

Geliştirici Araçları'ndan önceki ve sonraki durumu gösteren animasyonlu GIF. DevTools'un, ağaçta Yazılmış Kodu gösterdiği sonraki resimde artık "Hızlı Aç" menüsündeki hiçbir çerçeve dosyasını önermediğine ve sağda daha net bir yığın izleme gösterdiğine dikkat edin.

x_google_ignoreList kaynak eşlemesi uzantısı

Kaynak eşlemelerinde, yeni x_google_ignoreList alanı sources dizisine başvuruda bulunur ve bu kaynak eşlemesindeki bilinen tüm üçüncü taraf kaynakların dizinlerini listeler. Kaynak eşlemeyi ayrıştırırken Chrome Geliştirici Araçları, kodun hangi bölümlerinin yoksayılanlar listesine eklenmesi gerektiğini belirlemek için bunu kullanır.

Aşağıda, oluşturulan out.js dosyasının kaynak eşlemesi verilmiştir. Çıkış dosyasının oluşturulmasına katkıda bulunan iki orijinal sources vardır: foo.js ve lib.js. İlki web sitesi geliştiricisinin yazdığı bir şey, ikincisi ise kullandığı bir çerçevedir.

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

sourcesContent, bu orijinal kaynakların her ikisine de eklenmiştir. Chrome Geliştirici Araçları, bu dosyaları Hata Ayıklayıcı'da varsayılan olarak görüntüler:

  • Kaynaklar ağacında dosyalar olarak.
  • Hızlı Aç iletişim kutusunda gösterilir.
  • Bir kesme noktasında duraklatıldığında ve adım atma sırasında hata yığını izlemelerinde eşlenmiş çağrı karesi konumları olarak.

Bu kaynaklardan hangisinin birinci taraf kodu yoksa üçüncü taraf kodu olduğunu belirlemek için artık kaynak haritalarına eklenebilecek bir bilgi daha var:

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

Yeni x_google_ignoreList alanı, sources dizisine başvuruda bulunan tek bir dizin içerir: 1. Bu, lib.js ile eşlenen bölgelerin aslında yoksayılanlar listesine otomatik olarak eklenmesi gereken üçüncü taraf kodu olduğunu belirtir.

Aşağıda gösterilen daha karmaşık bir örnekte, 2, 4 ve 5 numaralı dizinler lib1.ts, lib2.coffee ve hmr.js ile eşlenen bölgelerin, yoksayılanlar listesine otomatik olarak eklenmesi gereken üçüncü taraf kodu olduğunu belirtir.

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

Çerçeve veya paketleyici geliştiricisiyseniz derleme işlemi sırasında oluşturulan kaynak haritalarının Chrome Geliştirici Araçları'ndaki bu yeni özelliklerden yararlanmak için bu alanı içerdiğinden emin olun.

Açısal olarak x_google_ignoreList

Angular 14.1.0 sürümünden itibaren node_modules ve webpack klasörlerinin içeriği “yoksayılacak” olarak işaretlenmiştir.

Bu, web paketinin Compiler modülüne bağlanan bir eklenti oluşturularak angular-cli ürününde yapılan bir değişiklikle gerçekleştirilmiştir.

Mühendislerimizin oluşturduğu web paketi eklentisi, PROCESS_ASSETS_STAGE_DEV_TOOLING aşamasına kancalar ekler ve web paketinin oluşturduğu ve tarayıcının yüklediği nihai öğeler için kaynak haritalarındaki x_google_ignoreList alanını doldurur.

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

Bağlı yığın izlemeler

Yığın izleme, "buraya nasıl geldim?" sorusunu yanıtlar. Ancak bu genellikle makinenin bakış açısından gerçekleşir ve geliştiricinin bakış açısıyla veya uygulama çalışma zamanının zihinsel modeliyle uyuşmayabilir. Bu durum özellikle bazı işlemlerin daha sonra eşzamansız olarak gerçekleşmesi planlandığında geçerlidir: Bu tür işlemlerin "kök nedenini" veya planlama tarafını bilmek yine de ilginç olabilir. Ancak bu, eşzamansız yığın izlemenin (stack trace) bir parçası olmayacaktır.

V8'de, setTimeout gibi standart tarayıcı planlama temel öğeleri kullanıldığında bu tür eşzamansız görevlerin takibi için dahili bir mekanizma bulunur. Bu tür durumlarda bu işlem varsayılan olarak yapılır, böylece geliştiriciler bunları inceleyebilir! Ancak daha karmaşık projelerde bu kadar basit değildir. Özellikle de bölge izleme, özel görev sıraya ekleme gibi daha gelişmiş planlama mekanizmalarına sahip bir çerçeve kullanıyorsanız ya da güncellemeleri zaman içinde çalıştırılan çeşitli çalışma birimlerine bölen bir çerçeve kullanıyorsanız.

DevTools bu sorunu çözmek için console nesnesinde "Async Stack Tagging API" adlı bir mekanizma sunar. Bu mekanizma, çerçeve geliştiricilerinin hem işlemlerin planlandığı konumları hem de bu işlemlerin yürütüldüğü yerleri belirtmesine olanak tanır.

Eş Zamansız Yığın Etiketleme API'sı

Eş Zamansız Yığın Etiketleme özelliği olmadan, çerçeveler tarafından karmaşık yollarla eşzamansız olarak yürütülen koda ait yığın izleri, planlandığı kodla hiçbir bağlantısı olmadan gösterilir.

Zaman uyumsuz olarak yürütülen bazı kodların yığın izidir ve planlandığı zamanla ilgili bilgi yoktur. Yalnızca "requestAnimationFrame" öğesi ile başlayan yığın izlemeyi gösterir, ancak planlandığı zamana ait bilgileri içermez.

Eş Zamansız Yığın Etiketleme ile bu bağlamı sağlamak mümkündür. Yığın izleme (stack trace) aşağıdaki gibi görünür:

Zaman uyumsuz olarak yürütülen bir kodun yığın izlemesi ve planlandığı zamanla ilgili bilgiler. Daha önce olduğundan farklı olarak yığın izlemeye "businessLogic" ve "schedule" öğesi içerdiğine dikkat edin.

Bunun için Async Stack Tagging API'nin sağladığı console.createTask() adlı yeni bir console yöntemini kullanın. İmzası aşağıdaki gibidir:

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

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

console.createTask() çağrıldığında, daha sonra eşzamansız kodu çalıştırmak için kullanabileceğiniz bir Task örneği döndürülür.

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

// Task Execution
task.run(f);

Eşzamansız işlemler de iç içe yerleştirilebilir ve "temel nedenler", yığın izlemede sırayla gösterilir.

Görevler istediğiniz sayıda çalıştırılabilir ve iş yükü her çalıştırma arasında değişiklik gösterebilir. Planlama sitesindeki çağrı yığını, görev nesnesi çöp toplanana kadar hatırlanır.

Angular'da Eş Zamansız Yığın Etiketleme API'sı

Angular'da, NgZone (Angular'ın eşzamansız görevler genelinde devam eden yürütme bağlamı) değişiklikler yapıldı.

Bir görev planlanırken mevcut olduğunda console.createTask() kullanılır. Ortaya çıkan Task örneği daha sonra kullanılmak üzere depolanır. NgZone, görevi başlattıktan sonra çalıştırmak için depolanan Task örneğini kullanır.

Bu değişiklikler, #46693 ve #46958 çekme istekleri aracılığıyla Angular'ın NgZone 0.11.8'ine ulaştı.

Kullanışlı Telefon Çerçeveleri

Çerçeveler, bir proje oluştururken genellikle HTML görünümlü kodu nihayetinde tarayıcıda çalışacak düz JavaScript'e dönüştüren Angular veya JSX şablonları gibi her türlü şablon dilinden kod üretir. Bazen, üretilen bu tür işlevlere pek kolay görünmeyen adlar verilir. Küçültüldükten sonra tek harfli adlar veya küçük oldukları halde anlaşılmasalar bile net olmayan ya da bilinmedik adlar verilebilir.

Angular'da yığın izlemelerde AppComponent_Template_app_button_handleClick_1_listener gibi adlara sahip çağrı çerçeveleri görmek normaldir.

Otomatik oluşturulan bir işlev adına sahip yığın izlemenin (stack trace) ekran görüntüsü.

Bu sorunu gidermek için Chrome Geliştirici Araçları artık bu işlevleri kaynak eşlemeleri aracılığıyla yeniden adlandırmayı desteklemektedir. Kaynak eşlemesinde, işlev kapsamının (yani parametre listesinin sol parantezi) başlangıcı için bir ad girişi varsa, çağrı çerçevesinin yığın izlemede bu adı görüntülemesi gerekir.

Açılarda Kullanışlı Arama Çerçeveleri

Angular'da çağrı çerçevelerini yeniden adlandırmak, devam eden bir çalışmadır. Bu iyileştirmelerin zaman içinde kademeli olarak uygulanmasını bekliyoruz.

Angular derleyicisi, yazarların yazdığı HTML şablonlarını ayrıştırırken TypeScript kodu oluşturur. Bu kod, sonunda tarayıcının yükleyip çalıştırdığı JavaScript koduna aktarılır.

Bu kod oluşturma süreci kapsamında kaynak eşlemeleri de oluşturulur. Şu anda kaynak eşlemelerinin "adlar" alanına işlev adlarını dahil etmenin ve oluşturulan kod ile orijinal kod arasındaki eşlemelerde bu adlara referans vermenin yollarını araştırıyoruz.

Örneğin, bir etkinlik işleyici için işlev oluşturulduysa ve işlevin adı küçültme sırasında uyumlu değilse veya kaldırıldıysa, kaynak eşlemeleri artık "adlar" alanına bu işlevin daha kolay adını içerebilir ve işlev kapsamının başlangıcına ilişkin eşleme artık bu ada (yani parametre listesinin sol parantezi) işaret edebilir. Ardından Chrome Geliştirici Araçları, yığın izlemelerdeki çağrı çerçevelerini yeniden adlandırmak için bu adları kullanır.

Geleceğe dönük olarak

Çalışmamızı doğrulamak için Angular'ı test pilotu olarak kullanmak harika bir deneyim oldu. Çerçeve geliştiricilerini dinlemeyi ve bu uzantı noktaları hakkında bize geri bildirim vermeyi çok isteriz.

Keşfetmek istediğimiz başka alanlar da var. Özel olarak, Geliştirici Araçları'nda profil oluşturma deneyiminin nasıl iyileştirileceğine bakalım.