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

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

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

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

अनदेखा किए जाने वाले कोड की सूची

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

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

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

ऐनिमेशन वाला एक GIF, जिसमें DevTools से पहले और बाद में दिखने वाले DevTools दिख रहे हैं. ध्यान दें कि बाद की इमेज में, 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 में इन नई सुविधाओं का इस्तेमाल किया जा सकेगा.

Angular में x_google_ignoreList

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

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

हमारे इंजीनियरों ने PROCESS_ASSETS_STAGE_DEV_TOOLING चरण में webpack प्लग इन बनाया है. यह प्लग इन, webpack से जनरेट होने वाली और ब्राउज़र से लोड होने वाली फ़ाइनल ऐसेट के लिए, सोर्स मैप में 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 Stack Tagging API

असाइन किए गए कोड के लिए, स्टैक ट्रेस की जानकारी तब नहीं दिखती, जब फ़्रेमवर्क के ज़रिए असाइन किए गए कोड को असाइन किए गए समय के बाद चलाया जाता है.

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

एक साथ काम नहीं करने वाले स्टैक को टैग करने की सुविधा की मदद से, यह कॉन्टेक्स्ट दिया जा सकता है. स्टैक ट्रेस इस तरह दिखता है:

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

ऐसा करने के लिए, console.createTask() नाम के नए console तरीके का इस्तेमाल करें. यह तरीका, एसिंक्रोनस स्टैक टैगिंग एपीआई उपलब्ध कराता है. इसके हस्ताक्षर इस प्रकार हैं:

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 में एसिंक्रोनस स्टैक टैगिंग एपीआई

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

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

ये बदलाव, पुल रिक्वेस्ट #46693 और #46958 के ज़रिए, Angular के NgZone 0.11.8 में किए गए हैं.

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

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

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

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

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

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

Angular में कॉल फ़्रेम का नाम बदलने की प्रोसेस जारी है. हमें उम्मीद है कि ये सुधार समय के साथ धीरे-धीरे लागू होंगे.

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

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

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

आगे की योजना

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

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