ব্যবহার না করা কোড সরিয়ে দিন

এই কোডল্যাবে, অব্যবহৃত এবং অপ্রয়োজনীয় ডিপেন্ডেন্সি সরিয়ে নিম্নলিখিত অ্যাপ্লিকেশনের পারফর্ম্যান্স উন্নত করুন।

অ্যাপের স্ক্রিনশট

পরিমাপ করুন

অপ্টিমাইজেশন যোগ করার আগে, কোনও ওয়েবসাইট কতটা ভালো পারফর্ম করে তা প্রথমে পরিমাপ করা সবসময়ই ভালো আইডিয়া।

  • সাইটের প্রিভিউ দেখতে, অ্যাপ দেখুন বিকল্পে প্রেস করুন। তারপর ফুল-স্ক্রিন পূর্ণ স্ক্রিন বিকল্পে প্রেস করুন।

এগিয়ে যান এবং আপনার পছন্দের বিড়ালছানার উপর ক্লিক করুন! Firebase-এর রিয়েল-টাইম ডেটাবেস এই অ্যাপ্লিকেশনে ব্যবহার করা হয়, যার ফলে স্কোর রিয়েল-টাইমে আপডেট হয় এবং অ্যাপ্লিকেশন ব্যবহারকারী অন্য সব ব্যক্তির সাথে সিঙ্ক করা হয়। 🐈

  1. DevTools খুলতে `Control+Shift+J` (বা Mac-এ `Command+Option+J`) প্রেস করুন।
  2. নেটওয়ার্ক ট্যাবে ক্লিক করুন।
  3. ক্যাশে বন্ধ করুন চেকবক্স বেছে নিন।
  4. অ্যাপটি আবার লোড করুন।

৯৯২ কেবি-র আসল বান্ডেল সাইজ

এই সাধারণ অ্যাপ্লিকেশনটি লোড করার জন্য প্রায় ১ এমবি মূল্যের জাভাস্ক্রিপ্ট পাঠানো হচ্ছে!

DevTools-এ প্রোজেক্ট সংক্রান্ত সতর্কতা দেখুন।

  • Console ট্যাবে ক্লিক করুন।
  • Filter ইনপুটের পাশে লেভেল ড্রপডাউনে Warnings চালু করা আছে কিনা তা নিশ্চিত করুন।

সতর্কতা ফিল্টার

  • দেখানো সতর্কতাটি দেখুন।

কনসোল সতর্কতা

Firebase, যা এই অ্যাপ্লিকেশনে ব্যবহৃত লাইব্রেরিগুলির মধ্যে একটি, ডেভেলপারদের সতর্ক করে একটি ভাল কাজ করছে যাতে তারা এর পুরো প্যাকেজটি ইমপোর্ট না করে, শুধুমাত্র ব্যবহৃত কম্পোনেন্টগুলি ইমপোর্ট করে। অন্যভাবে বলতে গেলে, এই অ্যাপ্লিকেশনে এমন কিছু অব্যবহৃত লাইব্রেরি আছে যা সরিয়ে দিলে এটি আরও দ্রুত লোড হবে।

এছাড়াও, এমন কিছু উদাহরণ আছে যেখানে নির্দিষ্ট লাইব্রেরি ব্যবহার করা হয়, তবে সেখানে আরও সহজ বিকল্প থাকতে পারে। অপ্রয়োজনীয় লাইব্রেরি সরানোর ধারণাটি এই টিউটোরিয়ালে পরে আলোচনা করা হয়েছে।

বান্ডেল বিশ্লেষণ করা হচ্ছে

অ্যাপ্লিকেশনে দুটি প্রধান ডিপেন্ডেন্সি আছে:

  • Firebase: এমন একটি প্ল্যাটফর্ম যা iOS, Android বা ওয়েব অ্যাপ্লিকেশনের জন্য একাধিক প্রয়োজনীয় পরিষেবা প্রদান করে। এখানে, প্রতিটি বিড়ালছানার তথ্য রিয়েল টাইমে স্টোর এবং সিঙ্ক করতে এর রিয়েলটাইম ডেটাবেস ব্যবহার করা হয়।
  • Moment.js: একটি ইউটিলিটি লাইব্রেরি যা জাভাস্ক্রিপ্টে তারিখ ম্যানেজ করা সহজ করে তোলে। প্রতিটি বিড়ালছানার জন্মতারিখ Firebase ডেটাবেসে স্টোর করা হয় এবং moment ব্যবহার করে সপ্তাহ হিসেবে তার বয়স গণনা করা হয়।

কীভাবে মাত্র দুটি ডিপেন্ডেন্সি প্রায় ১ এমবি সাইজের বান্ডেল তৈরি করতে পারে? এর একটি কারণ হল, যেকোনও ডিপেন্ডেন্সির নিজস্ব ডিপেন্ডেন্সি থাকতে পারে, তাই ডিপেন্ডেন্সি "ট্রি"-এর প্রতিটি ডেপথ/ব্রাঞ্চ বিবেচনা করলে, দুটির থেকে অনেক বেশি ডিপেন্ডেন্সি থাকে। অনেক ডিপেন্ডেন্সি অন্তর্ভুক্ত থাকলে, তুলনামূলকভাবে দ্রুত কোনও অ্যাপ্লিকেশন বড় হয়ে যাওয়া সহজ।

কী হচ্ছে তা আরও ভালোভাবে বুঝতে বান্ডলার বিশ্লেষণ করুন। এটি করতে সাহায্য করতে পারে এমন অনেক কমিউনিটি-বিল্ট টুল আছে, যেমন webpack-bundle-analyzer।

এই টুলের প্যাকেজটি আগে থেকেই অ্যাপে devDependency হিসেবে অন্তর্ভুক্ত করা আছে।

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

এর অর্থ হল, এটি সরাসরি ওয়েবপ্যাক কনফিগারেশন ফাইলে ব্যবহার করা যাবে। webpack.config.js-এর একদম শুরুতে এটি ইমপোর্ট করুন:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

এখন plugins অ্যারের মধ্যে ফাইলের একেবারে শেষে প্লাগ-ইন হিসেবে এটি যোগ করুন:

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

অ্যাপ্লিকেশনটি রিলোড হলে, আপনি অ্যাপের পরিবর্তে সম্পূর্ণ বান্ডেলের একটি ভিজ্যুয়ালাইজেশন দেখতে পাবেন।

Webpack Bundle Analyzer

বিড়ালছানা 🐱 দেখার মতো মিষ্টি না হলেও, এটি অত্যন্ত সহায়ক। যেকোনও প্যাকেজের উপর মাউস নিয়ে গেলে, তিনটি আলাদা উপায়ে সেটির সাইজ দেখানো হয়:

স্ট্যাট সাইজ ছোট করা বা কম্প্রেস করার আগে সাইজ।
পার্স করা সাইজ কম্পাইল করার পরে বান্ডেলের মধ্যে আসল প্যাকেজের সাইজ। webpack-এর ভার্সন ৪ (যা এই অ্যাপ্লিকেশনে ব্যবহার করা হয়) কম্পাইল করা ফাইলকে অটোমেটিক ছোট করে দেয়, তাই এটি স্ট্যাট সাইজের চেয়ে ছোট।
Gzipped সাইজ gzip এনকোডিংয়ের মাধ্যমে কম্প্রেস করার পরে প্যাকেজের সাইজ। এই বিষয়টি আলাদা একটি গাইডে কভার করা হয়েছে।

webpack-bundle-analyzer টুলের সাহায্যে, অব্যবহৃত বা অপ্রয়োজনীয় প্যাকেজ শনাক্ত করা সহজ হয়, যেগুলি বান্ডেলের একটি বড় শতাংশ তৈরি করে।

ব্যবহার করা হয়নি এমন প্যাকেজ সরানো হচ্ছে

ভিজ্যুয়ালাইজেশন থেকে দেখা যায় যে 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 নেটওয়ার্ক প্যানেল খুললে, বান্ডেলের সাইজ অনেক কমে গেছে বলে দেখা যায়:

বান্ডেলের সাইজ কমিয়ে ৪৮০ কেবি করা হয়েছে

বান্ডেলের সাইজের অর্ধেকের বেশি সরিয়ে দেওয়া হয়েছে। Firebase অনেক ধরনের পরিষেবা প্রদান করে এবং ডেভেলপারদের শুধুমাত্র সেইসব পরিষেবা অন্তর্ভুক্ত করার বিকল্প দেয় যেগুলি আসলে প্রয়োজন। এই অ্যাপ্লিকেশনে, সব ডেটা স্টোর ও সিঙ্ক করার জন্য শুধুমাত্র firebase/database ব্যবহার করা হয়েছে। firebase/app ইমপোর্ট, যা প্রতিটি আলাদা পরিষেবার জন্য API সারফেস সেট-আপ করে, সেটি সবসময় প্রয়োজন হয়।

lodash-এর মতো আরও অনেক জনপ্রিয় লাইব্রেরিও ডেভেলপারদের তাদের প্যাকেজের বিভিন্ন অংশ বেছে নিয়ে ইম্পোর্ট করার অনুমতি দেয়। খুব বেশি কাজ না করেই, কোনও অ্যাপ্লিকেশনে লাইব্রেরি ইমপোর্ট আপডেট করে শুধুমাত্র যা ব্যবহার করা হচ্ছে তা অন্তর্ভুক্ত করলে পারফর্ম্যান্সের উল্লেখযোগ্য উন্নতি হতে পারে।

যদিও বান্ডেলের সাইজ অনেকটাই কমানো হয়েছে, তবুও আরও অনেক কাজ বাকি আছে! 😈

অপ্রয়োজনীয় প্যাকেজ সরানো হচ্ছে

Firebase-এর মতো, moment লাইব্রেরির অংশগুলি ইম্পোর্ট করা ততটা সহজ নয়, তবে এটি কি সম্পূর্ণভাবে সরানো যেতে পারে?

প্রতিটি কিউট বিড়ালছানার জন্মদিন Firebase ডেটাবেসে Unix ফর্ম্যাটে (মিলিসেকেন্ড) স্টোর করা হয়।

Unix ফর্ম্যাটে সেভ করা জন্মতারিখ

এটি হল ১ জানুয়ারি, ১৯৭০ ০০:০০ UTC থেকে অতিবাহিত হওয়া মিলিসেকেন্ডের সংখ্যা দ্বারা উপস্থাপিত নির্দিষ্ট তারিখ ও সময়ের টাইমস্ট্যাম্প। বর্তমান তারিখ ও সময় যদি একই ফর্ম্যাটে গণনা করা যায়, তাহলে প্রতিটি বিড়ালছানার বয়স সপ্তাহে গণনা করার জন্য একটি ছোট ফাংশন সম্ভবত তৈরি করা যেতে পারে।

সবসময়ের মতো, এখানে দেখানো ধাপগুলি অনুসরণ করার সময় কপি ও পেস্ট না করার চেষ্টা করুন। 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>
    `})
});

এখন অ্যাপ্লিকেশনটি আবার লোড করুন এবং নেটওয়ার্ক প্যানেলটি আরও একবার দেখুন।

বান্ডেলের সাইজ কমিয়ে ২২৫ কেবি করা হয়েছে

আমাদের বান্ডেলের সাইজ আবার অর্ধেকের বেশি কমে গেছে!

উপসংহার

এই কোডল্যাবের মাধ্যমে, আপনি একটি নির্দিষ্ট বান্ডেল কীভাবে বিশ্লেষণ করবেন এবং অব্যবহৃত বা অপ্রয়োজনীয় প্যাকেজগুলি সরানো কেন এত কার্যকর হতে পারে সে সম্পর্কে আপনার একটি ভালো ধারণা থাকা উচিত। এই টেকনিকের সাহায্যে কোনও অ্যাপ্লিকেশন অপ্টিমাইজ করা শুরু করার আগে, এটি জানা গুরুত্বপূর্ণ যে বড় অ্যাপ্লিকেশনের ক্ষেত্রে এটি অনেক বেশি জটিল হতে পারে।

অব্যবহৃত লাইব্রেরি সরিয়ে দেওয়ার ব্যাপারে, বান্ডেলের কোন অংশ ব্যবহার করা হচ্ছে এবং কোন অংশ ব্যবহার করা হচ্ছে না তা খুঁজে বের করার চেষ্টা করুন। রহস্যজনক দেখতে কোনও প্যাকেজ, যা দেখে মনে হচ্ছে কোথাও ব্যবহার করা হচ্ছে না, সেটির ক্ষেত্রে এক ধাপ পিছিয়ে গিয়ে চেক করে দেখুন কোন টপ-লেভেল ডিপেন্ডেন্সির জন্য সেটি প্রয়োজন হতে পারে। Try to find a way to possibly decouple them from each other.

অপ্রয়োজনীয় লাইব্রেরি সরিয়ে দেওয়ার ক্ষেত্রে, বিষয়টি একটু বেশি জটিল হতে পারে। আপনার টিমের সাথে ঘনিষ্ঠভাবে কাজ করা এবং কোডবেসের অংশগুলি সহজ করার সম্ভাবনা আছে কিনা তা দেখা গুরুত্বপূর্ণ। এই অ্যাপ্লিকেশনে moment সরিয়ে দেওয়াটা সবসময় সঠিক কাজ বলে মনে হতে পারে, কিন্তু টাইম জোন এবং বিভিন্ন লোকাল ম্যানেজ করতে হলে কী হবে? অথবা তারিখ নিয়ে আরও জটিল কারসাজি থাকলে কী হবে? তারিখ/সময় ম্যানিপুলেট ও পার্স করার সময় পরিস্থিতি খুব জটিল হয়ে যেতে পারে এবং moment ও date-fns-এর মতো লাইব্রেরি এটিকে উল্লেখযোগ্যভাবে সহজ করে তোলে।

সবকিছুই হল ট্রেডঅফ এবং থার্ড-পার্টি লাইব্রেরির উপর নির্ভর না করে কাস্টম সমাধান রোল-আউট করার জটিলতা এবং প্রচেষ্টা আদৌ সার্থক কিনা তা পরিমাপ করা গুরুত্বপূর্ণ।