केस स्टडी: 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 ट्री में लिखा गया कोड दिखाता है. यह "क्विक ओपन" मेन्यू में किसी भी फ़्रेमवर्क फ़ाइल का सुझाव नहीं देता और दाईं ओर ज़्यादा साफ़ स्टैक ट्रेस दिखाता है.

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 फ़ोल्डर के कॉन्टेंट को “ध्यान न दें” के तौर पर मार्क किया गया है.

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

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

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 ऑब्जेक्ट पर “एसिंक्रोनस स्टैक टैगिंग एपीआई” नाम का एक तरीका उपलब्ध कराता है. इसकी मदद से, फ़्रेमवर्क डेवलपर यह बता पाते हैं कि कार्रवाइयों को कहां शेड्यूल करना है और कहां-कहां ये कार्रवाइयां की जा रही हैं.

एक साथ काम नहीं करने वाली स्टैक टैगिंग एपीआई

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

सिंक नहीं किए गए कुछ कोड का स्टैक ट्रेस, जिनमें इस बारे में कोई जानकारी नहीं है कि उसे कब शेड्यूल किया गया था. यह सिर्फ़ `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 इंस्टेंस का इस्तेमाल करेगा.

ये बदलाव, 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 में प्रोफ़ाइलिंग के अनुभव को बेहतर बनाने का तरीका.