केस स्टडी: DevTools की मदद से बेहतर एंगुलर डीबगिंग

डीबग करने का बेहतर अनुभव

पिछले कुछ महीनों में, Chrome DevTools टीम ने Angular टीम के साथ मिलकर Chrome DevTools में डीबग करने के अनुभव को बेहतर बनाया है. दोनों टीमों के लोगों ने साथ मिलकर काम किया और डेवलपर के लिए ऑथरिंग के नज़रिए: से वेब ऐप्लिकेशन को डीबग और प्रोफ़ाइल करने की दिशा में कदम उठाए. इससे उन्हें सोर्स लैंग्वेज और प्रोजेक्ट स्ट्रक्चर के मामले में, अपनी जानी-पहचानी और काम की जानकारी का ऐक्सेस मिला.

इस पोस्ट को बेहतर तरीके से समझने के लिए, हम यह देखते हैं कि इसे पाने के लिए, Angular और Chrome DevTools में कौनसे बदलाव करने की ज़रूरत है. इनमें से कुछ बदलाव Angular की मदद से दिखाए जाते हैं. हालांकि, इन्हें अन्य फ़्रेमवर्क पर भी लागू किया जा सकता है. Chrome DevTools की टीम अन्य फ़्रेमवर्क को बढ़ावा देती है, ताकि वे नए कंसोल एपीआई और सोर्स मैप एक्सटेंशन पॉइंट का इस्तेमाल कर सकें. इससे वे भी अपने उपयोगकर्ताओं को डीबग करने का बेहतर अनुभव दे पाएंगे.

अनदेखा करने वाला कोड

Chrome DevTools का इस्तेमाल करके ऐप्लिकेशन डीबग करते समय, लेखक आम तौर पर सिर्फ़ सिर्फ़ अपना कोड देखना चाहते हैं. वे नीचे दिए गए फ़्रेमवर्क या node_modules फ़ोल्डर में मौजूद कुछ डिपेंडेंसी नहीं देखना चाहते.

ऐसा करने के लिए, DevTools टीम ने सोर्स मैप के लिए एक एक्सटेंशन उपलब्ध कराया है, जिसका नाम x_google_ignoreList है. इस एक्सटेंशन का इस्तेमाल तीसरे पक्ष के सोर्स की पहचान करने के लिए किया जाता है. जैसे, फ़्रेमवर्क कोड या बंडलर से जनरेट किया गया कोड. जब कोई फ़्रेमवर्क इस एक्सटेंशन का इस्तेमाल करता है, तो लेखक उस कोड को अपने-आप छोड़ देते हैं जिसे वे देखना नहीं चाहते हैं या इसे पहले से मैन्युअल तरीके से कॉन्फ़िगर किए बिना आगे बढ़ना नहीं चाहते हैं.

Chrome DevTools, स्टैक ट्रेस, सोर्स ट्री, और क्विक ओपन डायलॉग में पहचाने गए कोड को अपने-आप छिपा सकता है. साथ ही, यह डीबगर में स्टेपिंग और फिर से शुरू करने के व्यवहार को बेहतर बनाता है.

DevTools से पहले और बाद में DevTools को दिखाने वाला ऐनिमेट किया गया GIF. ध्यान दें कि बाद में दिखाई गई इमेज DevTools, ट्री में लिखे गए कोड को कैसे दिखाता है, जो अब "क्विक ओपन" मेन्यू में किसी भी फ़्रेमवर्क फ़ाइल का सुझाव नहीं देता है. साथ ही, दाईं ओर ज़्यादा साफ़ स्टैक ट्रेस दिखाता है.

सेक्शन में दी गई है.

x_google_ignoreList सोर्स मैप एक्सटेंशन

सोर्स मैप में, नया x_google_ignoreList फ़ील्ड, sources कलेक्शन का रेफ़रंस देता है. साथ ही, उस सोर्स मैप में मौजूद तीसरे पक्ष के सभी सोर्स के इंडेक्स की सूची बनाता है. सोर्स मैप को पार्स करते समय, Chrome DevTools इसका इस्तेमाल यह पता करने के लिए करेगा कि कोड के किन सेक्शन को अनदेखा किया जाना चाहिए.

नीचे जनरेट की गई फ़ाइल out.js के लिए सोर्स मैप दिया गया है. आउटपुट फ़ाइल जनरेट करने के लिए, दो मूल sources हैं: foo.js और lib.js. पहला प्रॉडक्ट किसी वेबसाइट डेवलपर ने लिखा है और दूसरा फ़्रेमवर्क इस्तेमाल किया गया है.

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

इन दोनों मूल सोर्स के लिए sourcesContent को शामिल किया गया है और Chrome DevTools इन फ़ाइलों को डीबगर पर डिफ़ॉल्ट रूप से दिखाएगा:

  • सोर्स ट्री में फ़ाइलों के तौर पर.
  • क्विक ओपन डायलॉग में, नतीजों के तौर पर.
  • गड़बड़ी वाले स्टैक ट्रेस में मैप किए गए कॉल फ़्रेम की लोकेशन, ब्रेकपॉइंट पर रुकने के दौरान और कदम चलने के दौरान दिखती हैं.

एक अतिरिक्त जानकारी मौजूद है, जिसे अब सोर्स मैप में शामिल किया जा सकता है. इससे यह पता लगाया जा सकता है कि सोर्स के किस सोर्स का कोड पहला है या तीसरे पक्ष का:

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

नए x_google_ignoreList फ़ील्ड में, sources कलेक्शन का रेफ़रंस देने वाला सिंगल इंडेक्स होता है: 1. इससे पता चलता है कि lib.js के लिए मैप किए गए इलाके, तीसरे पक्ष के कोड हैं. इसलिए, इन्हें अनदेखा करने की सूची में अपने-आप जोड़ा जाना चाहिए.

नीचे दिए गए ज़्यादा जटिल उदाहरण में, इंडेक्स 2, 4, और 5 से पता चलता है कि lib1.ts, lib2.coffee, और hmr.js पर मैप किए गए क्षेत्र तीसरे पक्ष के हैं. साथ ही, ये कोड अनदेखा करने की सूची में अपने-आप जुड़ जाने चाहिए.

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

अगर आप फ़्रेमवर्क या बंडलर डेवलपर हैं, तो पक्का करें कि बिल्ड प्रोसेस के दौरान जनरेट किए गए सोर्स मैप में यह फ़ील्ड शामिल हो, ताकि Chrome DevTools की इन नई सुविधाओं का इस्तेमाल किया जा सके.

एंगुलर में x_google_ignoreList

Angular v14.1.0 से, node_modules और webpack फ़ोल्डर के कॉन्टेंट को “अनदेखा करने के लिए” के तौर पर मार्क किया गया है.

ऐसा angular-cli में बदलाव की वजह से हुआ. इसके लिए, एक ऐसा प्लगिन बनाया गया जो webpack के Compiler मॉड्यूल से जुड़ा हो

वह वेबपैक प्लगिन जिसे हमारे इंजीनियर PROCESS_ASSETS_STAGE_DEV_TOOLING स्टेज में हुक बनाते हैं. साथ ही, यह वेबपैक जनरेट करने और ब्राउज़र को लोड करने के लिए, सोर्स मैप में x_google_ignoreList फ़ील्ड को इकट्ठा करता है.

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

लिंक किए गए स्टैक ट्रेस

स्टैक ट्रेस की मदद से, “मैं यहां कैसे पहुंचा” वाले सवाल का जवाब देता है. हालांकि, कई बार ऐसा होता है कि ऐसा मशीन के नज़रिए से किया जाता है. यह ज़रूरी नहीं है कि यह ऐसा कुछ हो जो डेवलपर के नज़रिए या ऐप्लिकेशन रनटाइम के उनके मानसिक मॉडल से मेल खाता हो. ऐसा खास तौर पर तब होता है, जब कुछ ऑपरेशन एसिंक्रोनस रूप से बाद में होने के लिए शेड्यूल होते हैं: ऐसे ऑपरेशन की "रूट वजह" या शेड्यूल साइड को जानना अब भी दिलचस्प हो सकता है, लेकिन यह कुछ ऐसा है जो एसिंक्रोनस स्टैक ट्रेस का हिस्सा नहीं है.

जब स्टैंडर्ड ब्राउज़र शेड्यूलिंग प्रिमिटिव का इस्तेमाल किया जाता है, तो V8 में ऐसे एसिंक्रोनस टास्क को ट्रैक करने का अंदरूनी तरीका होता है, जैसे कि setTimeout. उन मामलों में डिफ़ॉल्ट रूप से ऐसा होता है, ताकि डेवलपर पहले से ही इनकी जांच कर सकें! हालांकि, ज़्यादा मुश्किल प्रोजेक्ट में, ऐसा करना उतना आसान नहीं होता. खास तौर पर, ऐसा तब होता है, जब शेड्यूल करने के ज़्यादा बेहतर तरीकों वाले फ़्रेमवर्क का इस्तेमाल किया जाता है. उदाहरण के लिए, ऐसा ऐप्लिकेशन जो ज़ोन ट्रैकिंग करता हो, टास्क की सूची बनाता हो या फिर अपडेट को समय के साथ काम की कई इकाइयों में बांट देता हो.

इसे ठीक करने के लिए, DevTools console ऑब्जेक्ट पर “Async Stack Tagging API” नाम का एक सिस्टम दिखाता है. इसकी मदद से, फ़्रेमवर्क डेवलपर उन दोनों जगहों के बारे में बता सकते हैं जहां कार्रवाइयां शेड्यूल की गई हैं. साथ ही, यह भी बताया जा सकता है कि ये कार्रवाइयां कहां पर होती हैं.

Async स्टैक टैगिंग एपीआई

Async स्टैक टैगिंग के बिना, उस कोड का स्टैक ट्रेस जो फ़्रेमवर्क के मुताबिक, एसिंक्रोनस तरीके से एक साथ लागू होता है, उस कोड से बिना किसी कनेक्शन के दिखता है जहां उसे शेड्यूल किया गया था.

एक साथ काम नहीं करने वाले कुछ कोड का स्टैक ट्रेस, जिसमें यह जानकारी नहीं है कि उसे कब शेड्यूल किया गया था. यह सिर्फ़ `requestAnimationFrame` से शुरू होने वाले स्टैक ट्रेस को दिखाता है. हालांकि, इसमें इसे शेड्यूल करने के समय से कोई जानकारी नहीं होती.

Async स्टैक टैगिंग के साथ यह संदर्भ दिया जा सकता है और स्टैक ट्रेस ऐसा दिखता है:

एक साथ काम नहीं करने वाले कुछ कोड का स्टैक ट्रेस. इसमें, यह जानकारी दी जाती है कि उसे कब शेड्यूल किया गया था. ध्यान दें कि पहले की तरह, इसमें स्टैक ट्रेस में `businessLogic` और `शेड्यूल` को कैसे शामिल किया गया है.

इसके लिए, console.createTask() नाम के एक नए console तरीके का इस्तेमाल करें, जो Async Stack Tagging API उपलब्ध है. उसके हस्ताक्षर इस तरह हैं:

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

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

console.createTask() को शुरू करने से Task इंस्टेंस मिलता है. इसका इस्तेमाल बाद में, एक साथ काम नहीं करने वाले कोड को चलाने के लिए किया जा सकता है.

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

// Task Execution
task.run(f);

एसिंक्रोनस ऑपरेशन को नेस्ट किया जा सकता है और स्टैक ट्रेस में “रूट की वजहें” क्रम में दिखाई जाएंगी.

टास्क कई बार चलाए जा सकते हैं और हर बार चलाने के बीच वर्क पेलोड अलग-अलग हो सकता है. अपॉइंटमेंट शेड्यूल करने की साइट पर मौजूद कॉल स्टैक को तब तक याद रखा जाएगा, जब तक टास्क ऑब्जेक्ट से ट्रैश इकट्ठा नहीं किया जाता.

Angular में Async Stack Tagging API

Angular में, NgZone में बदलाव किए गए हैं. यह Angular पर लागू होने वाला एक कॉन्टेक्स्ट है, जो एक साथ काम नहीं करने वाले टास्क में बना रहता है.

टास्क को शेड्यूल करते समय, उपलब्ध होने पर console.createTask() का इस्तेमाल किया जाता है. इससे, Task इंस्टेंस बाद में इस्तेमाल करने के लिए सेव कर लिया जाता है. टास्क को शुरू करने पर, NgZone, सेव किए गए Task इंस्टेंस का इस्तेमाल करके उसे चलाता है.

ये बदलाव Angular के NgZone 0.11.8 में, पुल के अनुरोधों #46693 और #46958 के ज़रिए आए.

फ़्रेंडली कॉल फ़्रेम

प्रोजेक्ट बनाते समय, फ़्रेमवर्क अक्सर सभी तरह की टेंप्लेटिंग भाषाओं से कोड जनरेट करते हैं. जैसे, Angular या JSX टेंप्लेट जो एचटीएमएल दिखने वाले कोड को सादी JavaScript में बदल देते हैं जो आखिर में ब्राउज़र में चलता है. कभी-कभी, इस तरह के जनरेट किए गए फ़ंक्शन को ऐसे नाम दिए जाते हैं जो बहुत काम के नहीं होते हैं. जैसे, छोटा किया गया कोई एक अक्षर वाला नाम या कुछ अनजान या अनजान नाम, जो तब भी काम के नहीं होते.

Angular में, स्टैक ट्रेस में AppComponent_Template_app_button_handleClick_1_listener जैसे नाम वाले कॉल फ़्रेम आम बात है.

अपने-आप जनरेट हुए फ़ंक्शन के नाम वाले स्टैक ट्रेस का स्क्रीनशॉट.

इसे ठीक करने के लिए, Chrome DevTools की मदद से अब सोर्स मैप की मदद से, इन फ़ंक्शन के नाम बदले जा सकते हैं. अगर किसी सोर्स मैप में, फ़ंक्शन के स्कोप (यानी पैरामीटर की सूची का बायां ब्रैकेट) की शुरुआत के लिए कोई नाम एंट्री है, तो कॉल फ़्रेम को स्टैक ट्रेस में वह नाम दिखाना चाहिए.

ऐंगुलर में फ़्रेंडली कॉल फ़्रेम

Angular में कॉल फ़्रेम का नाम बदलने के लिए, अभी तक काम नहीं किया जा रहा है. हमें उम्मीद है कि ये सुधार समय के साथ धीरे-धीरे और बेहतर होंगे.

लेखकों के लिखे एचटीएमएल टेंप्लेट को पार्स करते समय, Angular कंपाइलर TypeScript कोड जनरेट करता है. यह कोड, JavaScript कोड में बदल जाता है, जिसे ब्राउज़र लोड करता है और चलाता है.

कोड जनरेट करने की इस प्रोसेस के तहत, सोर्स मैप भी बनाए जाते हैं. फ़िलहाल, हम सोर्स मैप के “नाम” फ़ील्ड में फ़ंक्शन के नाम शामिल करने और जनरेट किए गए कोड और ओरिजनल कोड के बीच मैपिंग में उन नामों को रेफ़र करने के तरीके एक्सप्लोर कर रहे हैं.

उदाहरण के लिए, अगर इवेंट लिसनर के लिए कोई फ़ंक्शन जनरेट किया जाता है और छोटा करने के दौरान इसका नाम हटा दिया जाता है या उसे छोटा कर दिया जाता है, तो सोर्स मैप अब “नाम” फ़ील्ड में इस फ़ंक्शन के लिए ज़्यादा आसान नाम शामिल कर सकते हैं. साथ ही, फ़ंक्शन के स्कोप की शुरुआत की मैपिंग, अब इस नाम (पैरामीटर सूची का बायां ब्रैकेट) का रेफ़रंस ले सकती है. इसके बाद, Chrome DevTools इन नामों का इस्तेमाल, स्टैक ट्रेस में कॉल फ़्रेम का नाम बदलने के लिए करेगा.

आगे की जानकारी

हमारे काम की पुष्टि करने के लिए, टेस्ट पायलट के तौर पर Angular का इस्तेमाल करना शानदार अनुभव रहा. हमें फ़्रेमवर्क डेवलपर के सुझाव पाने में खुशी होगी. साथ ही, इन एक्सटेंशन पॉइंट के बारे में हमें सुझाव/राय दें या शिकायत करें.

हम ऐसे कई और क्षेत्र भी एक्सप्लोर करना चाहेंगे. खास तौर पर, DevTools में प्रोफ़ाइल बनाने के अनुभव को बेहतर बनाने का तरीका.