इस कोडलैब में, इस्तेमाल न होने वाली और ग़ैर-ज़रूरी डिपेंडेंसी हटाकर, इस ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाएं.

मापें
ऑप्टिमाइज़ेशन जोड़ने से पहले, यह देखना हमेशा अच्छा होता है कि वेबसाइट की परफ़ॉर्मेंस कैसी है.
- साइट की झलक देखने के लिए, ऐप्लिकेशन देखें को दबाएं. इसके बाद, फ़ुलस्क्रीन
को दबाएं.
आगे बढ़ें और अपनी पसंदीदा बिल्ली पर क्लिक करें! इस ऐप्लिकेशन में Firebase के रीयलटाइम डेटाबेस का इस्तेमाल किया जाता है. इसलिए, स्कोर रीयल-टाइम में अपडेट होता है और ऐप्लिकेशन का इस्तेमाल करने वाले हर व्यक्ति के साथ सिंक होता है. 🐈
- DevTools खोलने के लिए, `Control+Shift+J` (या Mac पर `Command+Option+J`) दबाएं.
- नेटवर्क टैब पर क्लिक करें.
- कैश मेमोरी की सुविधा बंद करें चेकबॉक्स को चुनें.
- ऐप्लिकेशन को फिर से लोड करें.

इस आसान ऐप्लिकेशन को लोड करने के लिए, करीब 1 एमबी की JavaScript भेजी जा रही है!
DevTools में प्रोजेक्ट से जुड़ी चेतावनियां देखें.
- कंसोल टैब पर क्लिक करें.
- पक्का करें कि
Filterइनपुट के बगल में मौजूद लेवल ड्रॉपडाउन में,Warningsचालू हो.

- दिखाई गई चेतावनी को देखें.

Firebase, इस ऐप्लिकेशन में इस्तेमाल की जाने वाली लाइब्रेरी में से एक है. यह डेवलपर को चेतावनी देकर उनकी मदद करता है, ताकि वे इसके पूरे पैकेज को इंपोर्ट न करें. इसके बजाय, सिर्फ़ उन कॉम्पोनेंट को इंपोर्ट करें जिनका इस्तेमाल किया जाता है. दूसरे शब्दों में, इस ऐप्लिकेशन में ऐसी लाइब्रेरी मौजूद हैं जिनका इस्तेमाल नहीं किया जा रहा है. इन्हें हटाकर, ऐप्लिकेशन को तेज़ी से लोड होने लायक बनाया जा सकता है.
ऐसे भी मामले होते हैं जब किसी खास लाइब्रेरी का इस्तेमाल किया जाता है, लेकिन हो सकता है कि कोई आसान विकल्प उपलब्ध हो. इस ट्यूटोरियल में आगे, गैर-ज़रूरी लाइब्रेरी को हटाने के बारे में बताया गया है.
बंडल का विश्लेषण किया जा रहा है
ऐप्लिकेशन में दो मुख्य डिपेंडेंसी हैं:
- Firebase: यह एक ऐसा प्लैटफ़ॉर्म है जो iOS, Android या वेब ऐप्लिकेशन के लिए कई काम की सेवाएं उपलब्ध कराता है. यहां इसके रीयलटाइम डेटाबेस का इस्तेमाल, हर बिल्ली के बच्चे की जानकारी को रीयल टाइम में सेव और सिंक करने के लिए किया जाता है.
- Moment.js: यह एक यूटिलिटी लाइब्रेरी है. इसकी मदद से, JavaScript में तारीखों को मैनेज करना आसान हो जाता है. हर बिल्ली के बच्चे के जन्म की तारीख, Firebase डेटाबेस में सेव की जाती है. साथ ही,
momentका इस्तेमाल करके, हफ़्तों में उसकी उम्र का हिसाब लगाया जाता है.
सिर्फ़ दो डिपेंडेंसी, बंडल के साइज़ को करीब 1 एमबी तक कैसे बढ़ा सकती हैं? इसकी एक वजह यह है कि किसी भी डिपेंडेंसी की अपनी डिपेंडेंसी हो सकती हैं. इसलिए, अगर डिपेंडेंसी "ट्री" की हर डेप्थ/ब्रांच को ध्यान में रखा जाए, तो दो से ज़्यादा डिपेंडेंसी हो सकती हैं. अगर किसी ऐप्लिकेशन में कई डिपेंडेंसी शामिल की जाती हैं, तो वह तेज़ी से बड़ा हो सकता है.
क्या हो रहा है, यह बेहतर तरीके से समझने के लिए बंडलर का विश्लेषण करें. कम्यूनिटी के बनाए गए ऐसे कई टूल हैं जिनकी मदद से यह काम किया जा सकता है. जैसे, webpack-bundle-analyzer.
इस टूल का पैकेज, ऐप्लिकेशन में पहले से ही devDependency के तौर पर शामिल है.
"devDependencies": {
//...
"webpack-bundle-analyzer": "^2.13.1"
},
इसका मतलब है कि इसे सीधे webpack कॉन्फ़िगरेशन फ़ाइल में इस्तेमाल किया जा सकता है.
इसे webpack.config.js की शुरुआत में इंपोर्ट करें:
const path = require("path");
//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
अब इसे plugins कलेक्शन में, फ़ाइल के आखिर में प्लगिन के तौर पर जोड़ें:
module.exports = {
//...
plugins: [
//...
new BundleAnalyzerPlugin()
]
};
ऐप्लिकेशन के फिर से लोड होने पर, आपको ऐप्लिकेशन के बजाय पूरे बंडल का विज़ुअलाइज़ेशन दिखना चाहिए.

यह बिल्लियों के बच्चों को देखने जितना प्यारा नहीं है 🐱, लेकिन फिर भी बहुत मददगार है. किसी भी पैकेज पर कर्सर घुमाने से, उसका साइज़ तीन अलग-अलग तरीकों से दिखता है:
| आंकड़ों का साइज़ | किसी भी तरह की काट-छांट या कंप्रेस करने से पहले का साइज़. |
|---|---|
| पार्स किया गया साइज़ | कंपाइल होने के बाद, बंडल में मौजूद असल पैकेज का साइज़. webpack का वर्शन 4 (जिसका इस्तेमाल इस ऐप्लिकेशन में किया जाता है), कंपाइल की गई फ़ाइलों को अपने-आप छोटा कर देता है. इस वजह से, यह स्टैट साइज़ से छोटा होता है. |
| Gzipped साइज़ | gzip एन्कोडिंग के साथ कंप्रेस किए जाने के बाद, पैकेज का साइज़. इस विषय के बारे में अलग गाइड में बताया गया है. |
webpack-bundle-analyzer टूल की मदद से, उन पैकेज की पहचान करना आसान हो जाता है जो इस्तेमाल नहीं किए जा रहे हैं या जिनकी ज़रूरत नहीं है. ये पैकेज, बंडल का एक बड़ा हिस्सा होते हैं.
इस्तेमाल नहीं किए जा रहे पैकेज हटाना
विज़ुअलाइज़ेशन से पता चलता है कि firebase पैकेज में सिर्फ़ डेटाबेस नहीं, बल्कि बहुत कुछ शामिल है. इसमें ये अतिरिक्त पैकेज शामिल हैं:
firestoreauthstoragemessagingfunctions
ये सभी Firebase की बेहतरीन सेवाएं हैं. इनके बारे में ज़्यादा जानने के लिए, दस्तावेज़ देखें. हालांकि, इनमें से किसी भी सेवा का इस्तेमाल ऐप्लिकेशन में नहीं किया जा रहा है. इसलिए, इन सभी को इंपोर्ट करने की कोई ज़रूरत नहीं है.
ऐप्लिकेशन को फिर से देखने के लिए, webpack.config.js में किए गए बदलावों को पहले जैसा करें:
- प्लग इन की सूची से
BundleAnalyzerPluginको हटाएं:
plugins: [
//...
new BundleAnalyzerPlugin()
];
- अब फ़ाइल के सबसे ऊपर मौजूद, इस्तेमाल न किए गए इंपोर्ट को हटाएं:
const path = require("path");
//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
अब ऐप्लिकेशन सामान्य रूप से लोड होना चाहिए. Firebase इंपोर्ट को अपडेट करने के लिए, src/index.js में बदलाव करें.
import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';
अब ऐप्लिकेशन के फिर से लोड होने पर, DevTools की चेतावनी नहीं दिखती. DevTools नेटवर्क पैनल खोलने पर, बंडल के साइज़ में काफ़ी कमी भी दिखती है:

बंडल के साइज़ को आधे से ज़्यादा कम कर दिया गया. Firebase कई तरह की सेवाएं देता है. साथ ही, डेवलपर को सिर्फ़ उन सेवाओं को शामिल करने का विकल्प देता है जिनकी उन्हें ज़रूरत है. इस ऐप्लिकेशन में, सारा डेटा सेव और सिंक करने के लिए सिर्फ़ firebase/database का इस्तेमाल किया गया था. firebase/app इंपोर्ट करना हमेशा ज़रूरी होता है. इससे हर सेवा के लिए, एपीआई का प्लैटफ़ॉर्म सेट अप होता है.
lodash जैसी कई अन्य लोकप्रिय लाइब्रेरी भी डेवलपर को अपने पैकेज के अलग-अलग हिस्सों को चुनिंदा तौर पर इंपोर्ट करने की अनुमति देती हैं. किसी ऐप्लिकेशन में लाइब्रेरी इंपोर्ट को अपडेट करके, सिर्फ़ इस्तेमाल किए जा रहे कॉम्पोनेंट को शामिल करने से, ऐप्लिकेशन की परफ़ॉर्मेंस में काफ़ी सुधार हो सकता है. इसके लिए, ज़्यादा मेहनत करने की ज़रूरत नहीं होती.
हालांकि, बंडल का साइज़ काफ़ी कम हो गया है, लेकिन अब भी बहुत कुछ करना बाकी है! 😈
ऐसे पैकेज हटाना जिनकी ज़रूरत नहीं है
Firebase के उलट, moment लाइब्रेरी के हिस्सों को आसानी से इंपोर्ट नहीं किया जा सकता. हालांकि, क्या इसे पूरी तरह से हटाया जा सकता है?
हर प्यारी बिल्ली के जन्म की तारीख, Firebase डेटाबेस में Unix फ़ॉर्मैट (मिलीसेकंड) में सेव की जाती है.

यह किसी खास तारीख और समय का टाइमस्टैंप होता है. इसे 1 जनवरी, 1970 को 00:00 यूटीसी के बाद से बीते हुए मिलीसेकंड की संख्या के तौर पर दिखाया जाता है. अगर मौजूदा तारीख और समय को एक ही फ़ॉर्मैट में कैलकुलेट किया जा सकता है, तो हर बिल्ली के बच्चे की उम्र हफ़्तों में पता लगाने के लिए, एक छोटा फ़ंक्शन बनाया जा सकता है.
हमेशा की तरह, यहां दिए गए कोड को कॉपी करके चिपकाने की कोशिश न करें. सबसे पहले, src/index.js में इंपोर्ट किए गए डेटा से moment को हटाएं.
import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';
हमारे डेटाबेस में वैल्यू में होने वाले बदलावों को मैनेज करने के लिए, एक Firebase इवेंट लिसनर मौजूद है:
favoritesRef.on("value", (snapshot) => { ... })
इसके ऊपर, दी गई तारीख से हफ़्तों की संख्या का हिसाब लगाने के लिए एक छोटा फ़ंक्शन जोड़ें:
const ageInWeeks = birthDate => {
const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
const diff = Math.abs((new Date).getTime() - birthDate);
return Math.floor(diff / WEEK_IN_MILLISECONDS);
}
इस फ़ंक्शन में, मौजूदा तारीख और समय (new Date).getTime() और जन्म की तारीख (birthDate आर्ग्युमेंट, जो पहले से ही मिलीसेकंड में है) के बीच के अंतर को मिलीसेकंड में कैलकुलेट किया जाता है. इसके बाद, इसे एक हफ़्ते में मौजूद मिलीसेकंड की संख्या से भाग दिया जाता है.
आखिर में, इवेंट लिसनर में moment के सभी इंस्टेंस हटाए जा सकते हैं. इसके लिए, इस फ़ंक्शन का इस्तेमाल करें:
favoritesRef.on("value", (snapshot) => {
const { kitties, favorites, names, birthDates } = snapshot.val();
favoritesScores = favorites;
kittiesList.innerHTML = kitties.map((kittiePic, index) => {
const birthday = moment(birthDates[index]);
return `
<li>
<img src=${kittiePic} onclick="favKittie(${index})">
<div class="extra">
<div class="details">
<p class="name">${names[index]}</p>
<p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
<p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
</div>
<p class="score">${favorites[index]} ❤</p>
</div>
</li>
`})
});
अब ऐप्लिकेशन को फिर से लोड करें और नेटवर्क पैनल को एक बार फिर से देखें.

हमारे बंडल का साइज़, आधे से भी कम हो गया!
नतीजा
इस कोडलैब की मदद से, आपको किसी खास बंडल का विश्लेषण करने का तरीका समझ आ गया होगा. साथ ही, आपको यह भी पता चल गया होगा कि इस्तेमाल न किए गए या ग़ैर-ज़रूरी पैकेज हटाने से क्या फ़ायदा होता है. इस तकनीक का इस्तेमाल करके किसी ऐप्लिकेशन को ऑप्टिमाइज़ करने से पहले, यह जानना ज़रूरी है कि बड़े ऐप्लिकेशन में यह प्रोसेस काफ़ी मुश्किल हो सकती है.
इस्तेमाल न की जा रही लाइब्रेरी हटाने के लिए, यह पता लगाने की कोशिश करें कि बंडल के किन हिस्सों का इस्तेमाल किया जा रहा है और किन हिस्सों का नहीं. अगर आपको कोई ऐसा पैकेज दिखता है जो रहस्यमयी लगता है और जिसका इस्तेमाल कहीं नहीं किया जा रहा है, तो एक कदम पीछे हटें और देखें कि टॉप-लेवल की किन डिपेंडेंसी को इसकी ज़रूरत पड़ सकती है. उन्हें एक-दूसरे से अलग करने का कोई तरीका ढूंढें.
गैर-ज़रूरी लाइब्रेरी हटाने की बात आती है, तो चीज़ें थोड़ी और मुश्किल हो सकती हैं. अपनी टीम के साथ मिलकर काम करना और यह देखना ज़रूरी है कि क्या कोड बेस के कुछ हिस्सों को आसान बनाया जा सकता है. इस ऐप्लिकेशन में moment को हटाना, हर बार सही लग सकता है. हालांकि, अगर टाइम ज़ोन और अलग-अलग भाषाओं को मैनेज करना हो, तो क्या होगा? या
क्या होगा अगर तारीखों में और भी मुश्किल बदलाव किए गए हों? तारीख/समय को पार्स और मैनिपुलेट करते समय, चीज़ें बहुत मुश्किल हो सकती हैं. हालांकि, moment और date-fns जैसी लाइब्रेरी इसे काफ़ी आसान बना देती हैं.
हर चीज़ के फ़ायदे और नुकसान होते हैं. इसलिए, यह आकलन करना ज़रूरी है कि तीसरे पक्ष की लाइब्रेरी पर भरोसा करने के बजाय, कस्टम समाधान को रोल आउट करने में लगने वाली मेहनत और जटिलता सही है या नहीं.