গ্র্যানুলার চাঙ্কিংয়ের মাধ্যমে Next.js ও Gatsby পেজ লোড হওয়ার পারফর্ম্যান্স উন্নত করা হয়েছে

Next.js এবং Gatsby-তে একটি নতুন ওয়েবপ্যাক চাঙ্কিং স্ট্র্যাটেজি পৃষ্ঠা লোডের পারফর্ম্যান্স উন্নত করতে ডুপ্লিকেট কোড কমিয়ে দেয়।

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

ভূমিকা

অনেক ওয়েব ফ্রেমওয়ার্কের মতো Next.js ও Gatsby তাদের কোর বান্ডলার হিসেবে webpack ব্যবহার করে। webpack v3 CommonsChunkPlugin নিয়ে এসেছে যাতে একক (বা কয়েকটি) "কমন" চাঙ্ক (বা চাঙ্কগুলি)-এ বিভিন্ন এন্ট্রি পয়েন্টের মধ্যে শেয়ার করা আউটপুট মডিউল সম্ভব হয়। শেয়ার করা কোড আলাদাভাবে ডাউনলোড করা এবং ব্রাউজার ক্যাশেতে আগে থেকে স্টোর করা যেতে পারে, যার ফলে লোডিং পারফর্ম্যান্স আরও ভালো হতে পারে।

এই প্যাটার্নটি অনেক সিঙ্গেল-পেজ অ্যাপ্লিকেশন ফ্রেমওয়ার্কের সাথে জনপ্রিয় হয়ে উঠেছে যা একটি এন্ট্রি পয়েন্ট এবং বান্ডেল কনফিগারেশন গ্রহণ করে যা দেখতে এইরকম:

সাধারণ এন্ট্রি পয়েন্ট ও বান্ডেল কনফিগারেশন

ব্যবহারিক হলেও, সমস্ত শেয়ার করা মডিউল কোডকে একটি একক চাঙ্কে বান্ডিল করার ধারণার নিজস্ব সীমাবদ্ধতা রয়েছে। প্রতিটি এন্ট্রি পয়েন্টে শেয়ার করা হয়নি এমন মডিউল সেইসব রুটের জন্য ডাউনলোড করা যেতে পারে যেগুলি এটি ব্যবহার করে না যার ফলে প্রয়োজনের চেয়ে বেশি কোড ডাউনলোড করা হয়। যেমন, page1 যখন common চাঙ্ক লোড করে, তখন এটি moduleC-এর জন্য কোড লোড করে, যদিও page1, moduleC ব্যবহার করে না। এই কারণে, আরও কিছু কারণের সাথে, webpack v4 নতুন একটির জন্য প্লাগ-ইন সরিয়ে দিয়েছে: SplitChunksPlugin।

উন্নত চাঙ্কিং

SplitChunksPlugin-এর ডিফল্ট সেটিংস বেশিরভাগ ব্যবহারকারীর জন্য ভাল কাজ করে। একাধিক রুটে ডুপ্লিকেট কোড ফেচ করা আটকানোর জন্য শর্তের উপর নির্ভর করে একাধিক স্প্লিট চাঙ্ক তৈরি করা হয়।

তবে, এই প্লাগ-ইন ব্যবহার করে এমন অনেক ওয়েব ফ্রেমওয়ার্ক এখনও চাঙ্ক স্প্লিটিংয়ের জন্য "সিঙ্গেল-কমন্স" অ্যাপ্রোচ অনুসরণ করে। উদাহরণস্বরূপ, Next.js একটি commons বান্ডেল তৈরি করবে যাতে এমন যেকোনও মডিউল থাকে যা ৫০%-এর বেশি পৃষ্ঠায় এবং সমস্ত ফ্রেমওয়ার্ক ডিপেন্ডেন্সিতে (react, react-dom, এবং আরও অনেক কিছু) ব্যবহার করা হয়।

const splitChunksConfigs = {
  …
  prod: {
    chunks: 'all',
    cacheGroups: {
      default: false,
      vendors: false,
      commons: {
        name: 'commons',
        chunks: 'all',
        minChunks: totalPages > 2 ? totalPages * 0.5 : 2,
      },
      react: {
        name: 'commons',
        chunks: 'all',
        test: /[\\/]node_modules[\\/](react|react-dom|scheduler|use-subscription)[\\/]/,
      },
    },
  },

যদিও শেয়ার করা চাঙ্কে ফ্রেমওয়ার্ক-নির্ভর কোড অন্তর্ভুক্ত করার অর্থ হল এটি যেকোনও এন্ট্রি পয়েন্টের জন্য ডাউনলোড এবং ক্যাশ করা যেতে পারে, অর্ধেকের বেশি পৃষ্ঠায় ব্যবহৃত সাধারণ মডিউল অন্তর্ভুক্ত করার ব্যবহার-ভিত্তিক হিউরিস্টিক খুব একটা কার্যকর নয়। এই অনুপাত পরিবর্তন করলে, শুধুমাত্র দুটি ফলাফলের মধ্যে একটি ঘটবে:

  • আপনি অনুপাত কমালে, আরও অপ্রয়োজনীয় কোড ডাউনলোড হয়ে যায়।
  • আপনি অনুপাত বাড়ালে, একাধিক রুট জুড়ে আরও কোড ডুপ্লিকেট হয়ে যায়।

এই সমস্যার সমাধান করতে, Next.js SplitChunksPlugin-এর জন্য অন্য কনফিগারেশন গ্রহণ করেছে যা যেকোনও রুটের জন্য অপ্রয়োজনীয় কোড কম করে।

  • যেকোনও যথেষ্ট বড় থার্ড-পার্টি মডিউল (১৬০ কেবির বেশি) তার নিজস্ব স্বতন্ত্র চাঙ্কে বিভক্ত করা হয়
  • ফ্রেমওয়ার্ক ডিপেন্ডেন্সির (react, react-dom এবং এই ধরনের) জন্য একটি আলাদা frameworks চাঙ্ক তৈরি করা হয়
  • প্রয়োজন অনুযায়ী শেয়ার করা চাঙ্ক তৈরি করা হয় (২৫টি পর্যন্ত)
  • চাঙ্ক তৈরি করার জন্য ন্যূনতম সাইজ পরিবর্তন করে ২০ কেবি করা হয়েছে

এই গ্র্যানুলার চাঙ্কিং স্ট্র্যাটেজি নিম্নলিখিত সুবিধা প্রদান করে:

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

আপনি webpack-config.ts-এ Next.js-এর গ্রহণ করা সম্পূর্ণ কনফিগারেশন দেখতে পারবেন।

আরও HTTP অনুরোধ

SplitChunksPlugin গ্র্যানুলার চাঙ্কিংয়ের ভিত্তি সংজ্ঞায়িত করেছে এবং Next.js-এর মতো ফ্রেমওয়ার্কে এই অ্যাপ্রোচ প্রয়োগ করা সম্পূর্ণ নতুন কোনও ধারণা ছিল না। তবে, অনেক ফ্রেমওয়ার্ক এখনও কয়েকটি কারণে একটি হিউরিস্টিক ও "কমন" বান্ডেল স্ট্র্যাটেজি ব্যবহার করে চলেছে। এর মধ্যে এই উদ্বেগও অন্তর্ভুক্ত যে আরও অনেক HTTP অনুরোধ সাইটের পারফর্ম্যান্সের উপর নেতিবাচক প্রভাব ফেলতে পারে।

ব্রাউজারগুলি শুধুমাত্র একটি একক অরিজিনে (Chrome-এর জন্য ৬টি) সীমিত সংখ্যক TCP কানেকশন খুলতে পারে, তাই একটি বান্ডলার দ্বারা আউটপুট করা চাঙ্কের সংখ্যা কমিয়ে দিলে তা নিশ্চিত করতে পারে যে অনুরোধের মোট সংখ্যা এই থ্রেশহোল্ডের নিচে থাকে। তবে, এটি শুধুমাত্র HTTP/1.1-এর ক্ষেত্রে প্রযোজ্য। HTTP/2-তে মাল্টিপ্লেক্সিং একই অরিজিনে একটি কানেকশন ব্যবহার করে সমান্তরালভাবে একাধিক অনুরোধ স্ট্রিম করার সুবিধা দেয়। অন্য কথায়, আমাদের বান্ডলারের মাধ্যমে নির্গত চাঙ্কের সংখ্যা সীমিত করার ব্যাপারে আমাদের সাধারণত চিন্তা করতে হয় না।

সব প্রধান ব্রাউজারে HTTP/2 কাজ করে। Chrome ও Next.js টিম দেখতে চেয়েছিল যে Next.js-এর একটি "commons" বান্ডেলকে একাধিক শেয়ার করা চাঙ্কে ভাগ করে অনুরোধের সংখ্যা বাড়ালে লোডিং পারফর্ম্যান্সে কোনও প্রভাব পড়ে কিনা। তারা maxInitialRequests প্রপার্টি ব্যবহার করে সমান্তরাল অনুরোধের সর্বাধিক সংখ্যা পরিবর্তন করার সময় একটি সাইটের পারফর্ম্যান্স পরিমাপ করার মাধ্যমে শুরু করেছিলেন।

অনুরোধের সংখ্যা বৃদ্ধি সহ পৃষ্ঠা লোড করার পারফর্ম্যান্স

একটি ওয়েব পেজে একাধিক ট্রায়ালের তিনটি রানের গড় হিসেবে, load, স্টার্ট-রেন্ডার এবং First Contentful Paint-এর সময় একই থাকে যখন প্রাথমিক অনুরোধের সর্বাধিক সংখ্যা পরিবর্তন করা হয় (৫ থেকে ১৫)। মজার ব্যাপার হল, আমরা লক্ষ্য করেছি যে শত শত অনুরোধে আগ্রাসীভাবে বিভক্ত করার পরেই পারফর্ম্যান্সের সামান্য ওভারহেড হয়েছে।

শত শত অনুরোধ সহ পৃষ্ঠা লোড করার পারফর্ম্যান্স

এটি দেখিয়েছে যে নির্ভরযোগ্য থ্রেশহোল্ডের (২০~২৫টি অনুরোধ) মধ্যে থাকলে লোডিং পারফর্ম্যান্স এবং ক্যাশিং দক্ষতার মধ্যে সঠিক ভারসাম্য বজায় থাকে। কিছু বেসলাইন টেস্টিংয়ের পরে, ২৫-কে maxInitialRequest কাউন্ট হিসেবে বেছে নেওয়া হয়েছে।

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

আরও বেশি চাঙ্কিংয়ের মাধ্যমে জাভাস্ক্রিপ্ট পেলোড কমানো

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

webpack একটি চাঙ্ক তৈরি করার জন্য ডিফল্ট ন্যূনতম সাইজ হিসেবে ৩০ কেবি ব্যবহার করে। তবে, maxInitialRequests-এর ভ্যালু ২৫-এর সাথে ২০ কেবি ন্যূনতম সাইজ যোগ করলে আরও ভাল ক্যাশিং হয়।

গ্র্যানুলার চাঙ্ক সহ সাইজ কমানো

Next.js সহ অনেক ফ্রেমওয়ার্ক, প্রতিটি রুট ট্রানজিশনের জন্য নতুন স্ক্রিপ্ট ট্যাগ ইনজেক্ট করতে ক্লায়েন্ট-সাইড রাউটিংয়ের (জাভাস্ক্রিপ্ট দ্বারা ম্যানেজ করা) উপর নির্ভর করে। কিন্তু বিল্ড টাইমে তারা কীভাবে এই ডাইনামিক চাঙ্কগুলি আগে থেকে নির্ধারণ করে?

Next.js সার্ভার-সাইড বিল্ড ম্যানিফেস্ট ফাইল ব্যবহার করে নির্ধারণ করে যে কোন আউটপুট চাঙ্কগুলি বিভিন্ন এন্ট্রি পয়েন্ট দ্বারা ব্যবহৃত হয়। ক্লায়েন্টকেও এই তথ্য প্রদান করার জন্য, প্রতিটি এন্ট্রি পয়েন্টের জন্য সব ডিপেন্ডেন্সি ম্যাপ করতে একটি সংক্ষিপ্ত ক্লায়েন্ট-সাইড বিল্ড ম্যানিফেস্ট ফাইল তৈরি করা হয়েছে।

// Returns a promise for the dependencies for a particular route
getDependencies (route) {
  return this.promisedBuildManifest.then(
    man => (man[route] && man[route].map(url => `/_next/${url}`)) || []
  )
}
Next.js অ্যাপ্লিকেশনে একাধিক শেয়ার করা চাঙ্কের আউটপুট।

এই নতুন গ্র্যানুলার চাঙ্কিং স্ট্র্যাটেজি প্রথমে Next.js-এ ফ্ল্যাগের পিছনে রোল-আউট করা হয়েছিল, যেখানে এটি প্রথম থেকেই ব্যবহার করতে শুরু করা বেশ কিছু ব্যবহারকারীর উপর পরীক্ষা করা হয়েছিল। অনেকেই দেখেছেন যে তাদের সম্পূর্ণ সাইটের জন্য ব্যবহৃত মোট জাভাস্ক্রিপ্ট উল্লেখযোগ্যভাবে হ্রাস পেয়েছে:

ওয়েবসাইট মোট JS পরিবর্তন % পার্থক্য
https://www.barnebys.com/ -২৩৮ কেবি -২৩%
https://sumup.com/ -২২০ কেবি ৩০% ছাড়
https://www.hashicorp.com/ -১১ এমবি -৭১%
জাভাস্ক্রিপ্ট সাইজ কমানো - সব রুট জুড়ে (কমপ্রেস করা)

চূড়ান্ত ভার্সনটি ডিফল্ট হিসেবে ভার্সন ৯.২-এ শিপ করা হয়েছে।

Gatsby

Gatsby সাধারণ মডিউল সংজ্ঞায়িত করার জন্য ব্যবহার-ভিত্তিক হিউরিস্টিক ব্যবহার করার একই পদ্ধতি অনুসরণ করত:

config.optimization = {
  …
  splitChunks: {
    name: false,
    chunks: `all`,
    cacheGroups: {
      default: false,
      vendors: false,
      commons: {
        name: `commons`,
        chunks: `all`,
        // if a chunk is used more than half the components count,
        // we can assume it's pretty global
        minChunks: componentsCount > 2 ? componentsCount * 0.5 : 2,
      },
      react: {
        name: `commons`,
        chunks: `all`,
        test: /[\\/]node_modules[\\/](react|react-dom|scheduler)[\\/]/,
      },

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

ওয়েবসাইট মোট JS পরিবর্তন % পার্থক্য
https://www.gatsbyjs.org/ -৬৮০ কেবি -২২%
https://www.thirdandgrove.com/ -৩৯০ কেবি ২৫% ছাড়
https://ghost.org/ -১.১ এমবি -৩৫%
https://reactjs.org/ -৮০ কেবি -৮%
জাভাস্ক্রিপ্ট সাইজ কমানো - সব রুট জুড়ে (কমপ্রেস করা)

তারা কীভাবে এই লজিক তাদের ওয়েবপ্যাক কনফিগারেশনে প্রয়োগ করেছে তা বুঝতে PR দেখুন, যা v2.20.7-এ ডিফল্ট হিসেবে শিপ করা হয়েছে।

উপসংহার

গ্র্যানুলার চাঙ্ক শিপিংয়ের ধারণা Next.js, Gatsby বা webpack-এর জন্য নির্দিষ্ট নয়। ফ্রেমওয়ার্ক বা মডিউল বান্ডলার যাই ব্যবহার করা হোক না কেন, অ্যাপ্লিকেশন যদি বড় "কমন" বান্ডেল অ্যাপ্রোচ অনুসরণ করে, তাহলে প্রত্যেকেরই অ্যাপ্লিকেশনের চাঙ্কিং স্ট্র্যাটেজি উন্নত করার কথা বিবেচনা করা উচিত।

  • আপনি যদি ভ্যানিলা React অ্যাপ্লিকেশনে একই চাঙ্কিং অপ্টিমাইজেশন প্রয়োগ করতে চান, তাহলে এই স্যাম্পেল React অ্যাপ দেখুন। এটি গ্র্যানুলার চাঙ্কিং স্ট্র্যাটেজির একটি সরলীকৃত ভার্সন ব্যবহার করে এবং আপনার সাইটে একই ধরনের লজিক প্রয়োগ করা শুরু করতে আপনাকে সাহায্য করতে পারে।
  • রোলআপের জন্য, ডিফল্ট হিসেবে গ্র্যানুলারভাবে চাঙ্ক তৈরি করা হয়। আপনি ম্যানুয়ালি আচরণ কনফিগার করতে চাইলে, manualChunks দেখুন।