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

angular-cli में बदलाव करके, ऐसा किया गया. इसके लिए, वेबपैक के 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” फ़ील्ड में इस फ़ंक्शन के लिए आसान नाम शामिल किया जा सकता है. साथ ही, फ़ंक्शन के स्कोप की शुरुआत के लिए मैपिंग में अब इस नाम का रेफ़रंस दिया जा सकता है. इसका मतलब है कि पैरामीटर सूची का बायां ब्रैकेट. इसके बाद, Chrome DevTools इन नामों का इस्तेमाल करके, स्टैक ट्रेस में कॉल फ़्रेम का नाम बदल देगा.

आगे की योजना

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

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