উন্নত Next.js এবং Gatsby পেজ লোড কর্মক্ষমতা দানাদার চঙ্কিং সহ

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

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

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

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

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

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

উন্নত Chunking

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

যাইহোক, এই প্লাগইন ব্যবহার করে এমন অনেক ওয়েব ফ্রেমওয়ার্ক এখনও খণ্ড বিভক্ত করার জন্য একটি "একক-কমন" পদ্ধতি অনুসরণ করে। উদাহরণ স্বরূপ, Next.js একটি commons বান্ডেল তৈরি করবে যাতে 50%-এর বেশি পৃষ্ঠা এবং সমস্ত ফ্রেমওয়ার্ক নির্ভরতা ( 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 এর জন্য একটি ভিন্ন কনফিগারেশন গ্রহণ করেছে যা যেকোনো রুটের জন্য অপ্রয়োজনীয় কোড কমিয়ে দেয়।

  • যে কোনো পর্যাপ্ত বড় তৃতীয় পক্ষের মডিউল (160 KB-এর বেশি) তার নিজস্ব পৃথক অংশে বিভক্ত হয়
  • ফ্রেমওয়ার্ক নির্ভরতার জন্য একটি পৃথক frameworks খণ্ড তৈরি করা হয়েছে ( react , react-dom , এবং তাই)
  • যতগুলি ভাগ করা প্রয়োজন ততগুলি ভাগ করা হয়েছে (25টি পর্যন্ত)
  • একটি খণ্ড তৈরি করার জন্য সর্বনিম্ন আকার 20 KB এ পরিবর্তিত হয়৷

এই দানাদার চঙ্কিং কৌশল নিম্নলিখিত সুবিধা প্রদান করে:

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

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

আরও HTTP অনুরোধ

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

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

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

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

একটি একক ওয়েব পৃষ্ঠায় একাধিক ট্রায়ালের গড়ে তিন রানের মধ্যে, load , স্টার্ট-রেন্ডার এবং ফার্স্ট কনটেন্টফুল পেইন্ট টাইম সবই একই থাকে যখন সর্বাধিক প্রাথমিক অনুরোধ গণনার পরিবর্তন হয় (5 থেকে 15 পর্যন্ত)। মজার ব্যাপার হল, আমরা শত শত অনুরোধে আক্রমনাত্মকভাবে বিভক্ত হওয়ার পরেই সামান্য পারফরম্যান্স ওভারহেড লক্ষ্য করেছি।

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

এটি দেখায় যে একটি নির্ভরযোগ্য থ্রেশহোল্ডের অধীনে থাকা (20~25 অনুরোধ) লোডিং কর্মক্ষমতা এবং ক্যাশিং দক্ষতার মধ্যে সঠিক ভারসাম্য বজায় রাখে। কিছু বেসলাইন পরীক্ষার পরে, 25 maxInitialRequest গণনা হিসাবে নির্বাচিত হয়েছিল।

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

জাভাস্ক্রিপ্ট পেলোড হ্রাস বৃদ্ধি chunking সঙ্গে

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

ওয়েবপ্যাক একটি খণ্ড তৈরি করার জন্য ডিফল্ট ন্যূনতম আকার হিসাবে 30 KB ব্যবহার করে। যাইহোক, এর পরিবর্তে 20 KB ন্যূনতম আকারের সাথে 25-এর একটি 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 অ্যাপ্লিকেশনে একাধিক ভাগ করা অংশের আউটপুট।

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

ওয়েবসাইট মোট JS পরিবর্তন % পার্থক্য
https://www.barnebys.com/ -238 কেবি -23%
https://sumup.com/ -220 কেবি -30%
https://www.hashicorp.com/ -11 এমবি -71%
জাভাস্ক্রিপ্টের আকার হ্রাস - সমস্ত রুট জুড়ে (সংকুচিত)

চূড়ান্ত সংস্করণটি ডিফল্টরূপে 9.2 সংস্করণে পাঠানো হয়েছিল।

গ্যাটসবি

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

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/ -680 KB -22%
https://www.thirdandgrove.com/ -390 KB -25%
https://ghost.org/ -1.1 এমবি -৩৫%
https://reactjs.org/ -80 কেবি -8%
জাভাস্ক্রিপ্টের আকার হ্রাস - সমস্ত রুট জুড়ে (সংকুচিত)

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

উপসংহার

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

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