DevTools के आर्किटेक्चर को रीफ़्रेश करना: DevTools में सीएसएस इन्फ़्रास्ट्रक्चर को आधुनिक बनाना
यह पोस्ट, ब्लॉग पोस्ट की एक सीरीज़ का हिस्सा है. इसमें, DevTools के आर्किटेक्चर में किए जा रहे बदलावों और इसे बनाने के तरीके के बारे में बताया गया है. हम बताएंगे कि DevTools में सीएसएस पहले कैसे काम करती थी और हमने DevTools में अपनी सीएसएस को कैसे आधुनिक बनाया है. ऐसा, JavaScript फ़ाइलों में सीएसएस लोड करने के लिए, वेब स्टैंडर्ड सलूशन पर माइग्रेट करने की तैयारी के लिए किया गया है.
DevTools में सीएसएस की पिछली स्थिति
DevTools ने सीएसएस को दो अलग-अलग तरीकों से लागू किया है: पहला, DevTools के लेगसी पार्ट में इस्तेमाल की जाने वाली सीएसएस फ़ाइलों के लिए और दूसरा, DevTools में इस्तेमाल किए जा रहे आधुनिक वेब कॉम्पोनेंट के लिए.
DevTools में सीएसएस लागू करने की सुविधा कई साल पहले तय की गई थी और अब यह पुरानी हो गई है. DevTools में module.json
पैटर्न का इस्तेमाल किया जाता है. इन फ़ाइलों को हटाने में काफ़ी मेहनत की गई है. इन फ़ाइलों को हटाने में आखिरी रुकावट, resources
सेक्शन है. इसका इस्तेमाल सीएसएस फ़ाइलों को लोड करने के लिए किया जाता है.
हम अलग-अलग संभावित समाधानों को एक्सप्लोर करने में समय बिताना चाहते थे, ताकि उन्हें सीएसएस मॉड्यूल स्क्रिप्ट में बदला जा सके. इसका मकसद, लेगसी सिस्टम की वजह से हुए तकनीकी क़र्ज़ को खत्म करना था. साथ ही, सीएसएस मॉड्यूल स्क्रिप्ट पर माइग्रेट करने की प्रोसेस को आसान बनाना था.
DevTools में मौजूद सभी सीएसएस फ़ाइलों को 'लेगसी' माना जाता था, क्योंकि उन्हें module.json
फ़ाइल का इस्तेमाल करके लोड किया गया था. इस फ़ाइल को हटाने की प्रोसेस जारी है. सभी सीएसएस फ़ाइलों को resources
में module.json
फ़ाइल में, सीएसएस फ़ाइल की उसी डायरेक्ट्री में लिस्ट किया जाना चाहिए.
बची हुई 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 के बाकी हिस्सों में इंपोर्ट किए गए कॉन्टेंट से अलग होंगे. इस वजह से, बिना स्टाइल वाले कॉन्टेंट का फ़्लैश (FOUC) दिखेगा. सीएसएस मॉड्यूल स्क्रिप्ट पर माइग्रेट करना मुश्किल होगा, क्योंकि इंपोर्ट को साफ़ तौर पर जोड़ना होगा और <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
ऑब्जेक्ट के तौर पर इंपोर्ट करने का तरीका ढूंढा, ताकि हम इसे शैडो DOM में जोड़ सकें. DevTools, पिछले कुछ सालों से शैडो DOM का इस्तेमाल करता है. इसके लिए, हमने adoptedStyleSheets
प्रॉपर्टी का इस्तेमाल किया.
बंडलर के विकल्प
हमें सीएसएस फ़ाइलों को CSSStyleSheet
ऑब्जेक्ट में बदलने का तरीका चाहिए था, ताकि हम TypeScript फ़ाइल में आसानी से बदलाव कर सकें. हमने Rollup और webpack, दोनों को संभावित बंडलर के तौर पर चुना, ताकि वे हमारे लिए यह बदलाव कर सकें. DevTools, अपने प्रोडक्शन बिल्ड में पहले से ही Rollup का इस्तेमाल करता है. हालांकि, प्रोडक्शन बिल्ड में किसी भी बंडलर को जोड़ने पर, हमारे मौजूदा बिल्ड सिस्टम के साथ काम करते समय परफ़ॉर्मेंस से जुड़ी समस्याएं हो सकती हैं. Chromium के GN बिल्ड सिस्टम के साथ इंटिग्रेशन करने से, बंडल करना ज़्यादा मुश्किल हो जाता है. इसलिए, बंडलर, Chromium के मौजूदा बिल्ड सिस्टम के साथ अच्छी तरह से इंटिग्रेट नहीं होते.
इसके बजाय, हमने GN के मौजूदा बिल्ड सिस्टम का इस्तेमाल करने का विकल्प चुना, ताकि यह बदलाव हमारे लिए किया जा सके.
DevTools में सीएसएस का इस्तेमाल करने का नया तरीका
नए तरीके में, किसी खास शैडो DOM में स्टाइल जोड़ने के लिए adoptedStyleSheets
का इस्तेमाल किया जाता है. साथ ही, GN बिल्ड सिस्टम का इस्तेमाल करके CSSStyleSheet ऑब्जेक्ट जनरेट किए जाते हैं. इन ऑब्जेक्ट को 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 पहले से ही कोड को एब्स्ट्रैक्ट सिंटैक्स ट्री(संक्षिप्त रूप में, AST) के बारे में जानकारी मिलती है. साथ ही, हम उन कॉल नोड के बारे में क्वेरी कर सकते हैं जो सीएसएस को रजिस्टर करने के लिए किए गए कॉल थे.
माइग्रेशन के लिए ESLint के नियम लिखते समय, हमें सबसे बड़ी समस्या एज केस कैप्चर करने में आई. हम यह पक्का करना चाहते थे कि हम यह तय कर पाएं कि किन एज केस को कैप्चर करना है और किन को मैन्युअल तरीके से माइग्रेट करना है. हम यह भी पक्का करना चाहते थे कि हम उपयोगकर्ता को बता सकें कि इंपोर्ट की गई .css.js
फ़ाइल, बिल्ड सिस्टम से अपने-आप जनरेट नहीं हो रही है. इससे रनटाइम पर, 'फ़ाइल नहीं मिली' वाली गड़बड़ियां नहीं होती हैं.
माइग्रेशन के लिए ESLint नियमों का इस्तेमाल करने का एक नुकसान यह था कि हम सिस्टम में ज़रूरी GN बिल्ड फ़ाइल को नहीं बदल पाए. उपयोगकर्ता को हर डायरेक्ट्री में मैन्युअल तरीके से ये बदलाव करने होते थे. हालांकि, इसके लिए ज़्यादा काम करना पड़ता था, लेकिन यह पुष्टि करने का एक अच्छा तरीका था कि इंपोर्ट की जा रही हर .css.js
फ़ाइल, असल में बिल्ड सिस्टम से जनरेट की गई है.
कुल मिलाकर, इस माइग्रेशन के लिए ESLint के नियमों का इस्तेमाल करना काफ़ी मददगार रहा. इससे हम पुराने कोड को नए इन्फ़्रास्ट्रक्चर पर तेज़ी से माइग्रेट कर पाए. साथ ही, एएसटी के तुरंत उपलब्ध होने का मतलब है कि हम नियम में कई एज केस भी मैनेज कर सकते हैं. साथ ही, ESLint के फ़िक्सर एपीआई का इस्तेमाल करके, उन्हें अपने-आप ठीक कर सकते हैं.
आगे क्या?
फ़िलहाल, Chromium DevTools में मौजूद सभी वेब कॉम्पोनेंट को माइग्रेट कर दिया गया है, ताकि इनलाइन स्टाइल के बजाय नए सीएसएस इन्फ़्रास्ट्रक्चर का इस्तेमाल किया जा सके. नए सिस्टम का इस्तेमाल करने के लिए, registerRequiredCSS
के ज़्यादातर लेगसी इस्तेमाल को भी माइग्रेट कर दिया गया है. अब आपको ज़्यादा से ज़्यादा module.json
फ़ाइलें हटानी हैं. इसके बाद, आने वाले समय में सीएसएस मॉड्यूल स्क्रिप्ट लागू करने के लिए, इस मौजूदा इन्फ़्रास्ट्रक्चर को माइग्रेट करना है!
झलक वाले चैनल डाउनलोड करना
Chrome कैनरी, डेवलपर या बीटा को अपने डिफ़ॉल्ट डेवलपमेंट ब्राउज़र के तौर पर इस्तेमाल करें. इन झलक वाले चैनलों की मदद से, आपको DevTools की नई सुविधाओं का ऐक्सेस मिलता है. साथ ही, इनसे आपको वेब प्लैटफ़ॉर्म के सबसे नए एपीआई की जांच करने में मदद मिलती है. इसके अलावा, इनकी मदद से उपयोगकर्ताओं से पहले ही अपनी साइट पर समस्याओं का पता लगाया जा सकता है!
Chrome DevTools की टीम से संपर्क करना
DevTools से जुड़ी नई सुविधाओं, अपडेट या किसी भी अन्य चीज़ के बारे में चर्चा करने के लिए, यहां दिए गए विकल्पों का इस्तेमाल करें.
- crbug.com पर जाकर, हमें सुझाव/राय दें या शिकायत करें. साथ ही, किसी सुविधा का अनुरोध करें.
- DevTools में ज़्यादा विकल्प > सहायता > DevTools से जुड़ी समस्या की शिकायत करें का इस्तेमाल करके, DevTools से जुड़ी समस्या की शिकायत करें.
- @ChromeDevTools पर ट्वीट करें.
- DevTools के YouTube वीडियो में नया क्या है या DevTools के बारे में सलाह देने वाले YouTube वीडियो पर टिप्पणियां करें.