इस्तेमाल न होने वाले कोड हटा दें

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

ऐप्लिकेशन का स्क्रीनशॉट

दूरी मापें

ऑप्टिमाइज़ेशन जोड़ने से पहले, यह मेज़र करना बेहतर होता है कि कोई वेबसाइट कैसा परफ़ॉर्म कर रही है.

  • साइट की झलक देखने के लिए, ऐप्लिकेशन देखें दबाएं. इसके बाद, फ़ुलस्क्रीन फ़ुलस्क्रीन दबाएं.

आगे बढ़ें और अपने पसंदीदा बिल्ली के बच्चे पर क्लिक करें! Firebase के रीयल टाइम डेटाबेस का इस्तेमाल इस ऐप्लिकेशन में किया जाता है. इसी वजह से, स्कोर रीयल-टाइम में अपडेट होता है. साथ ही, यह ऐप्लिकेशन इस्तेमाल करने वाले हर दूसरे व्यक्ति के साथ सिंक हो जाता है. 🐈

  1. DevTools खोलने के लिए, `Control+Shift+J` (या Mac पर `Command+Option+J`) दबाएं.
  2. नेटवर्क टैब पर क्लिक करें.
  3. कैश मेमोरी बंद करें चेकबॉक्स चुनें.
  4. ऐप्लिकेशन को फिर से लोड करें.

ओरिजनल बंडल का साइज़ 992 केबी

इस आसान ऐप्लिकेशन को लोड करने के लिए, करीब 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 (जिसका इस्तेमाल इस ऐप्लिकेशन में किया जाता है) अपने-आप कंपाइल की गई फ़ाइलों को छोटा कर देता है. इसलिए, यह आंकड़ों के साइज़ से छोटा है.
Gzip किया गया साइज़ gzip एन्कोडिंग के साथ कंप्रेस करने के बाद पैकेज का आकार. इस विषय के बारे में एक अलग गाइड में बताया गया है.

वेबपैक-बंडल-विश्लेषण टूल की मदद से, बंडल के एक बड़े प्रतिशत में शामिल ऐसे पैकेज की पहचान करना आसान हो जाता है जिन्हें इस्तेमाल नहीं किया गया है या जिनकी ज़रूरत नहीं है.

इस्तेमाल नहीं किए गए पैकेज को हटाना

विज़ुअलाइज़ेशन से पता चलता है कि firebase पैकेज में सिर्फ़ डेटाबेस से बहुत ज़्यादा चीज़ें शामिल हैं. इसमें इस तरह के अतिरिक्त पैकेज शामिल हैं:

  • firestore
  • auth
  • storage
  • messaging
  • functions

ये सभी बेहतरीन सेवाएं हैं जिन्हें 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 नेटवर्क पैनल खोलने पर, बंडल के साइज़ में अच्छी कमी दिखती है:

बंडल का साइज़ कम करके 480 केबी किया गया

बंडल का आधे से ज़्यादा साइज़ हटा दिया गया. 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>
    `})
});

अब ऐप्लिकेशन को फिर से लोड करें और एक बार फिर से नेटवर्क पैनल पर नज़र डालें.

बंडल का साइज़ कम करके 225 केबी किया गया

हमारे बंडल का साइज़ फिर से आधे से ज़्यादा हो गया!

नतीजा

इस कोडलैब से, आपको इस बात की अच्छी समझ होनी चाहिए कि किसी खास बंडल का विश्लेषण कैसे किया जाना चाहिए. साथ ही, आपको इस बात की भी जानकारी होनी चाहिए कि इस्तेमाल न किए गए या ग़ैर-ज़रूरी पैकेज को हटाना क्यों फ़ायदेमंद है. किसी ऐप्लिकेशन को इस तकनीक की मदद से ऑप्टिमाइज़ करने से पहले, यह जानना ज़रूरी है कि बड़े ऐप्लिकेशन में यह काम काफ़ी जटिल हो सकता है.

इस्तेमाल नहीं की गई लाइब्रेरी को हटाने के बारे में, यह पता करने की कोशिश करें कि बंडल के कौनसे हिस्से इस्तेमाल किए जा रहे हैं और कौनसे नहीं. रहस्यमयी दिखने वाले पैकेज के लिए, जिसे कहीं इस्तेमाल नहीं किया जा रहा है, थोड़ा पीछे जाएं और देखें कि किन टॉप-लेवल डिपेंडेंसी की ज़रूरत हो सकती है. उन्हें एक-दूसरे से हटाने का तरीका ढूँढने की कोशिश करें.

जब ग़ैर-ज़रूरी लाइब्रेरी को हटाने की बात आती है, तो चीज़ें थोड़ी और जटिल हो सकती हैं. अपनी टीम के साथ मिलकर काम करना और यह देखना ज़रूरी है कि कोड बेस के हिस्सों को आसान बनाया जा सकता है या नहीं. इस ऐप्लिकेशन से moment को हटाने पर ऐसा लगता है कि हर बार ऐसा करना सही होगा, लेकिन क्या होगा अगर टाइम ज़ोन और अलग-अलग जगहों को हैंडल करने की ज़रूरत हो? या अगर तारीख में और भी जटिल बदलाव होते, तो क्या होता? तारीखों/समय में हेर-फेर और पार्स करते समय चीज़ें बहुत मुश्किल हो सकती हैं. साथ ही, moment और date-fns जैसी लाइब्रेरी में बदलाव करना बहुत आसान हो जाता है.

हर चीज़ का नज़ाकत होती है और इस बात का आकलन करना ज़रूरी है कि तीसरे पक्ष की लाइब्रेरी पर निर्भर रहने के बजाय, कस्टम समाधान रोल आउट करने की जटिलता पर निर्भर है या नहीं.