DevTools में सीएसएस इन्फ़्रास्ट्रक्चर को आधुनिक बनाना

DevTools आर्किटेक्चर रीफ़्रेश: DevTools में सीएसएस इन्फ़्रास्ट्रक्चर को आधुनिक बनाया जा रहा है

यह पोस्ट ब्लॉग पोस्ट की एक सीरीज़ का हिस्सा है. इसमें, DevTools के आर्किटेक्चर में किए जा रहे बदलावों और उसे बनाने के तरीके के बारे में बताया है. हम आपको बताएंगे कि DevTools में सीएसएस ने अब तक किस तरह काम किया है. साथ ही, यह भी बताएंगे कि हमने JavaScript फ़ाइलों में सीएसएस लोड करने के लिए, वेब के स्टैंडर्ड समाधान पर माइग्रेट करने की तैयारी के लिए, DevTools में अपने सीएसएस को किस तरह से आधुनिक बनाया है.

DevTools में सीएसएस की पिछली स्थिति

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

DevTools में लागू किए गए सीएसएस को कई साल पहले तय किया गया था और अब यह पुराना हो गया है. DevTools अब module.json पैटर्न का इस्तेमाल नहीं कर रहा है और इन फ़ाइलों को हटाने की बहुत कोशिश की गई है. इन फ़ाइलों को हटाने से रोकने वाला आखिरी ब्लॉक resources सेक्शन है. इसका इस्तेमाल सीएसएस फ़ाइलों में लोड करने के लिए किया जाता है.

हम ऐसे अलग-अलग समाधान ढूंढने में समय लगाना चाहते थे जिन्हें बाद में सीएसएस मॉड्यूल स्क्रिप्ट में बदला जा सके. इसका मकसद पुराने सिस्टम की वजह से आने वाले तकनीकी क़र्ज़ को हटाना था. साथ ही, सीएसएस मॉड्यूल स्क्रिप्ट पर माइग्रेशन की प्रोसेस को भी आसान बनाना था.

DevTools में मौजूद सभी सीएसएस फ़ाइलों को 'लेगसी' माना गया, क्योंकि उन्हें module.json फ़ाइल का इस्तेमाल करके लोड किया गया था. इसे हटाने की प्रोसेस जारी है. सभी सीएसएस फ़ाइलों को, सीएसएस फ़ाइल वाली डायरेक्ट्री में मौजूद module.json फ़ाइल में, resources के तहत सूची में रखना ज़रूरी था.

बची हुई module.json फ़ाइल का एक उदाहरण:

{
  "resources": [
    "serviceWorkersView.css",
    "serviceWorkerUpdateCycleView.css"
  ]
}

इसके बाद, ये सीएसएस फ़ाइलें, Root.Runtime.cachedResources नाम के ग्लोबल ऑब्जेक्ट मैप में अपने-आप जानकारी भर देंगी. ऐसा, उनके कॉन्टेंट के पाथ से मैपिंग के तौर पर होगा. DevTools में स्टाइल जोड़ने के लिए, आपको registerRequiredCSS को कॉल करना होगा. इसमें उस फ़ाइल का सटीक पाथ होगा जिसे आपको लोड करना है.

registerRequiredCSS कॉल का उदाहरण:

constructor() {
  …
  this.registerRequiredCSS('ui/legacy/components/quick_open/filteredListWidget.css');
  …
}

इससे सीएसएस फ़ाइल का कॉन्टेंट वापस लाया जाएगा और appendStyle फ़ंक्शन का इस्तेमाल करके, उसे पेज में <style> एलिमेंट के तौर पर शामिल किया जाएगा:.

appendStyle फ़ंक्शन, जो इनलाइन स्टाइल एलिमेंट का इस्तेमाल करके सीएसएस जोड़ता है:

const content = Root.Runtime.cachedResources.get(cssFile) || '';

if (!content) {
  console.error(cssFile + ' not preloaded. Check module.json');
}

const styleElement = document.createElement('style');
styleElement.textContent = content;
node.appendChild(styleElement);

कस्टम एलिमेंट का इस्तेमाल करके, मॉडर्न वेब कॉम्पोनेंट लॉन्च करने पर, हमने शुरुआत में यह तय किया था कि कॉम्पोनेंट फ़ाइलों में इनलाइन <style> टैग के ज़रिए, सीएसएस का इस्तेमाल किया जाएगा. इससे खुद ही कुछ समस्याएं आईं:

  • सिंटैक्स हाइलाइट की सुविधा मौजूद नहीं है. इनलाइन सीएसएस के लिए सिंटैक्स हाइलाइट करने वाले प्लगिन, सिंटैक्स हाइलाइट करने और .css फ़ाइलों में लिखे गए सीएसएस के लिए अपने-आप पूरा होने वाली सुविधाओं की तरह अच्छे नहीं होते.
  • परफ़ॉर्मेंस ओवरहेड बनाएं. इनलाइन सीएसएस का मतलब यह भी था कि लिंटिंग के लिए दो पास की ज़रूरत होती है: एक सीएसएस फ़ाइलों के लिए और दूसरा इनलाइन सीएसएस के लिए. यह परफ़ॉर्मेंस ओवरहेड था. अगर सभी सीएसएस को स्टैंडअलोन सीएसएस फ़ाइलों में लिखा जाता, तो हम इसे हटा सकते थे.
  • छोटा करने की सुविधा में चुनौती. इनलाइन सीएसएस को आसानी से छोटा नहीं किया जा सका, इसलिए किसी भी सीएसएस को छोटा नहीं किया गया. DevTools की रिलीज़ के लिए तैयार की गई फ़ाइल का साइज़ भी बढ़ा दिया गया है. ऐसा, एक ही वेब कॉम्पोनेंट के कई इंस्टेंस से पेश किए गए डुप्लीकेट सीएसएस की वजह से हुआ है.

मेरे इंटर्नशिप प्रोजेक्ट का मकसद सीएसएस इन्फ़्रास्ट्रक्चर के लिए ऐसा समाधान खोजना था जो लेगसी इन्फ़्रास्ट्रक्चर और DevTools में इस्तेमाल होने वाले नए वेब कॉम्पोनेंट, दोनों के साथ काम करता हो.

संभावित समाधानों के बारे में पता लगाना

समस्या को दो अलग-अलग हिस्सों में बांटा जा सकता है:

  • यह पता लगाना कि बिल्ड सिस्टम, सीएसएस फ़ाइलों पर कैसे काम करता है.
  • यह पता लगाना कि DevTools की मदद से सीएसएस फ़ाइलों को कैसे इंपोर्ट और इस्तेमाल किया जाता है.

हमने हर हिस्से के लिए अलग-अलग संभावित समाधानों पर गौर किया है और उनके बारे में नीचे बताया गया है.

सीएसएस फ़ाइलें इंपोर्ट की जा रही हैं

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

इन वजहों से, @import स्टेटमेंट और टैग, DevTools के लिए सही नहीं लगे. ये DevTools के बाकी सभी आइटम में, इंपोर्ट के साथ एक जैसे नहीं होंगे. इसकी वजह से, फ़्लैश ऑफ़ अनस्टाइल कॉन्टेंट (एफ़ओयूसी) हो जाता है. CSS मॉड्यूल स्क्रिप्ट पर माइग्रेट करना मुश्किल होगा, क्योंकि इंपोर्ट को साफ़ तौर पर जोड़ना और <link> टैग की तुलना में अलग तरीके से मैनेज करना पड़ता.

const output = LitHtml.html`
<style> @import "css/styles.css"; </style>
<button> Hello world </button>`
const output = LitHtml.html`
<link rel="stylesheet" href="styles.css">
<button> Hello World </button>`

@import या <link> का इस्तेमाल करके समस्या को ठीक किया जा सकता है.

इसके बजाय, हमने सीएसएस फ़ाइल को CSSStyleSheet ऑब्जेक्ट के तौर पर इंपोर्ट करने का तरीका ढूंढने का विकल्प चुना है, ताकि हम उसे अपनी adoptedStyleSheets प्रॉपर्टी का इस्तेमाल करके, Shadow Dom (DevTools) में कुछ सालों के लिए Shadow DOM का इस्तेमाल करता है" में जोड़ सकें.

बंडलर विकल्प

हमें सीएसएस फ़ाइलों को CSSStyleSheet ऑब्जेक्ट में बदलने के तरीके की ज़रूरत थी, ताकि हम TypeScript फ़ाइल में उसमें आसानी से बदलाव कर सकें. हमने अपने लिए यह बदलाव करने के लिए, Rollup और webpack दोनों को संभावित बंडलर माना. DevTools पहले से ही अपने प्रोडक्शन बिल्ड में रोलअप का इस्तेमाल करता है. हालांकि, प्रोडक्शन बिल्ड में बंडलर जोड़ने से, हमारे मौजूदा बिल्ड सिस्टम के साथ काम करते समय परफ़ॉर्मेंस से जुड़ी समस्याएं हो सकती हैं. Chromium के GN बिल्ड सिस्टम के साथ हमारे इंटिग्रेशन की वजह से, बंडल करना ज़्यादा मुश्किल हो जाता है. इसलिए, बंडलर मौजूदा Chromium बिल्ड सिस्टम के साथ ठीक से इंटिग्रेट नहीं हो पाते.

इसके बजाय, हमने अपने लिए इस बदलाव के लिए मौजूदा जीएन बिल्ड सिस्टम का इस्तेमाल किया.

DevTools में सीएसएस इस्तेमाल करने का नया इंफ़्रास्ट्रक्चर

इस नए समाधान में, किसी खास शैडो DOM में स्टाइल जोड़ने के लिए adoptedStyleSheets का इस्तेमाल करना शामिल है. साथ ही, GN बिल्ड सिस्टम का इस्तेमाल करके, ऐसे CSSStyleSheet ऑब्जेक्ट को जनरेट करने के लिए, adoptedStyleSheets का इस्तेमाल करना शामिल है जिन्हें document या ShadowRoot के ज़रिए स्वीकार किया जा सकता है.

// CustomButton.ts

// Import the CSS style sheet contents from a JS file generated from CSS
import customButtonStyles from './customButton.css.js';
import otherStyles from './otherStyles.css.js';

export class CustomButton extends HTMLElement{
  …
  connectedCallback(): void {
    // Add the styles to the shadow root scope
    this.shadow.adoptedStyleSheets = [customButtonStyles, otherStyles];
  }
}

adoptedStyleSheets का इस्तेमाल करने के कई फ़ायदे हैं. जैसे:

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

इस समस्या को हल करने के लिए, आपको सिर्फ़ यह याद था कि import स्टेटमेंट के लिए, .css.js फ़ाइल इंपोर्ट करना ज़रूरी था. इमारत बनाने के दौरान GN को सीएसएस फ़ाइल जनरेट करने देने के लिए, हमने generate_css_js_files.js स्क्रिप्ट लिखी है. बिल्ड सिस्टम अब हर सीएसएस फ़ाइल को प्रोसेस करता है और उसे ऐसी JavaScript फ़ाइल में बदल देता है जो डिफ़ॉल्ट रूप से, CSSStyleSheet ऑब्जेक्ट एक्सपोर्ट करती है. यह बहुत अच्छा है, क्योंकि हम सीएसएस फ़ाइल को इंपोर्ट कर सकते हैं और इसे आसानी से इस्तेमाल कर सकते हैं. इसके अलावा, अब हम फ़ाइल का साइज़ बचाते हुए, प्रोडक्शन बिल्ड को आसानी से छोटा भी कर सकते हैं:

const styles = new CSSStyleSheet();
styles.replaceSync(
  // In production, we also minify our CSS styles
  /`${isDebug ? output : cleanCSS.minify(output).styles}
  /*# sourceURL=${fileName} */`/
);

export default styles;

स्क्रिप्ट से जनरेट किया गया iconButton.css.js का उदाहरण.

ESLint नियमों का इस्तेमाल करके, लेगसी कोड को माइग्रेट करना

वेब कॉम्पोनेंट को आसानी से मैन्युअल तरीके से माइग्रेट किया जा सकता था. हालांकि, registerRequiredCSS के लेगसी इस्तेमाल के डेटा को माइग्रेट करने की प्रोसेस ज़्यादा ज़रूरी थी. लेगसी स्टाइल को रजिस्टर करने वाले दो मुख्य फ़ंक्शन, registerRequiredCSS और createShadowRootWithCoreStyles थे. हमने यह तय किया कि इन कॉल को माइग्रेट करने के चरण मैकेनिकल थे, इसलिए हम ESLint नियमों का इस्तेमाल करके, सुधार लागू कर सकते थे और लेगसी कोड को अपने-आप माइग्रेट कर सकते थे. DevTools पहले से ही, DevTools कोडबेस के लिए पसंद के मुताबिक बनाए गए कई नियमों का इस्तेमाल करता है. इससे मदद मिली, क्योंकि ESLint पहले से ही कोड को ऐब्स्ट्रैक्ट सिंटैक्स ट्री(abbr. एएसटी) और हम उन खास कॉल नोड से क्वेरी कर सकते हैं जिन्हें सीएसएस को रजिस्टर करने के लिए कॉल किया गया था.

माइग्रेशन के लिए ESLint नियम लिखते समय, हमें सबसे बड़ी समस्या आई, गंभीर मामलों को इकट्ठा करना. हम यह पक्का करना चाहते थे कि हमारे बीच सही संतुलन बना रहे. साथ ही, यह भी पता हो कि किन किनारे के केस कैप्चर करने से काम के हैं और किन चीज़ों को मैन्युअल तरीके से माइग्रेट करना चाहिए. हम यह भी पक्का करना चाहते थे कि जब सिस्टम, इंपोर्ट की गई .css.js फ़ाइल अपने-आप जनरेट नहीं कर रहा हो, तो हम उपयोगकर्ता को इसकी सूचना दे पाएं. ऐसा करने से, रनटाइम के दौरान किसी भी फ़ाइल में गड़बड़ी नहीं मिलती.

माइग्रेशन के लिए ESLint इस्तेमाल करने का एक नुकसान यह था कि हम सिस्टम में ज़रूरी GN बिल्ड फ़ाइल को नहीं बदल सके. उपयोगकर्ता को ये बदलाव हर डायरेक्ट्री में मैन्युअल तौर पर करने होते थे. हालांकि, इसमें ज़्यादा काम करना पड़ता था, लेकिन इस तरीके से यह पुष्टि की जा सकती थी कि इंपोर्ट की जा रही हर .css.js फ़ाइल असल में बिल्ड सिस्टम से जनरेट होती है.

कुल मिलाकर, इस माइग्रेशन के लिए ESLint नियमों का इस्तेमाल करना वाकई मददगार था, क्योंकि हम लेगसी कोड को तेज़ी से नए इंफ़्रास्ट्रक्चर पर माइग्रेट कर पाए. साथ ही, AST को आसानी से उपलब्ध होने का मतलब है कि हम नियम में कई किनारों के मामलों को भी हैंडल कर सकते थे और ESLint के ठीक करने वाले एपीआई का इस्तेमाल करके, उन्हें आसानी से अपने-आप ठीक कर सकते थे.

अगला कदम क्या है?

अब तक, Chromium DevTools के सभी वेब कॉम्पोनेंट को माइग्रेट किया गया है. ऐसा इनलाइन स्टाइल का इस्तेमाल करने के बजाय, नए सीएसएस इन्फ़्रास्ट्रक्चर का इस्तेमाल करने के लिए किया गया है. registerRequiredCSS के ज़्यादातर लेगसी इस्तेमाल, नए सिस्टम का इस्तेमाल करने के लिए माइग्रेट कर दिए गए हैं. अब बस ज़्यादा से ज़्यादा module.json फ़ाइलें हटाना बाकी है. इसके बाद, आने वाले समय में सीएसएस मॉड्यूल स्क्रिप्ट लागू करने के लिए, इस मौजूदा इंफ़्रास्ट्रक्चर को माइग्रेट करें!

झलक दिखाने वाले चैनलों को डाउनलोड करें

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

Chrome DevTools टीम से संपर्क करना

पोस्ट में मौजूद नई सुविधाओं और बदलावों या DevTools से जुड़ी किसी भी अन्य चीज़ के बारे में बताने के लिए, नीचे दिए गए विकल्पों का इस्तेमाल करें.

  • crbug.com के ज़रिए हमें कोई सुझाव या सुझाव सबमिट करें.
  • DevTools में ज़्यादा विकल्प   ज़्यादा दिखाएं   > सहायता > DevTools से जुड़ी समस्याओं की शिकायत करें पर जाकर, DevTools से जुड़ी समस्या की शिकायत करें.
  • @ChromeDevTool पर ट्वीट करें.
  • DevTools YouTube वीडियो या DevTools सलाह वाले YouTube वीडियो में नया क्या है, इस बारे में टिप्पणियां करें.