बारीकी से अलग-अलग सेक्शन में बांटने के साथ-साथ Next.js और Gatsby पेज लोड होने की प्रोसेस को बेहतर बनाया गया

Next.js और Gatsby में एक नई वेबपैक चंकिंग रणनीति, पेज लोड की परफ़ॉर्मेंस को बेहतर बनाने के लिए डुप्लीकेट कोड को कम करती है.

Chrome, कई टूल और सेवाओं के साथ साथ मिलकर काम कर रहा है फ़्रेमवर्क शामिल हैं. हाल ही में कई नए ऑप्टिमाइज़ेशन Next.js के लोड होने की परफ़ॉर्मेंस को बेहतर बनाने के लिए जोड़ा गया और गैट्सबी. इस लेख में चंकिंग की बेहतर रणनीति के बारे में बताया गया है जो अब दोनों फ़्रेमवर्क में डिफ़ॉल्ट रूप से शिप किया जाता है.

परिचय

कई वेब फ़्रेमवर्क की तरह, Next.js और Gatsby, webpack को मुख्य वेब फ़्रेमवर्क के तौर पर इस्तेमाल करते हैं बंडलर. webpack v3 पेश किया गया CommonsChunkPlugin ताकि ये काम किए जा सकें किसी एक (या कुछ) "कॉमन" में अलग-अलग एंट्री पॉइंट के बीच शेयर किए गए आउटपुट मॉड्यूल डेटा का हिस्सा (या हिस्से). शेयर किए गए कोड को अलग से डाउनलोड करके, ब्राउज़र की कैश मेमोरी में सेव किया जा सकता है. साथ ही, इसे ब्राउज़र की कैश मेमोरी में सेव किया जा सकता है इससे परफ़ॉर्मेंस बेहतर होती है.

यह पैटर्न, एक पेज के कई ऐप्लिकेशन फ़्रेमवर्क के साथ लोकप्रिय हुआ. इसमें एंट्रीपॉइंट का इस्तेमाल किया गया और बंडल कॉन्फ़िगरेशन जो कुछ ऐसा दिखता है:

एंट्रीपॉइंट और बंडल का कॉन्फ़िगरेशन

यह व्यावहारिक है, लेकिन शेयर किए गए सभी मॉड्यूल कोड को एक हिस्से में बंडल करने के कॉन्सेप्ट में सीमित कर दिया है. हर एंट्री पॉइंट पर शेयर नहीं किए गए मॉड्यूल, उन रूट के लिए डाउनलोड किए जा सकते हैं जहां इसका इस्तेमाल नहीं किया जाता जिसकी वजह से ज़रूरत से ज़्यादा कोड डाउनलोड हो जाते हैं. उदाहरण के लिए, जब page1 लोड होता है common वाला हिस्सा, यह moduleC के लिए कोड लोड करता है, भले ही page1, moduleC का इस्तेमाल नहीं करता. इस वजह से, कुछ अन्य समस्याओं के साथ-साथ, webpack v4 ने नए प्लगिन के इस्तेमाल को बढ़ावा देने के लिए प्लगिन को हटा दिया एक: SplitChunksPlugin.

बेहतर चंकिंग

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 केबी से ज़्यादा) को अलग-अलग हिस्सों में बांट दिया जाता है समूह
  • फ़्रेमवर्क डिपेंडेंसी के लिए एक अलग frameworks डेटा ग्रुप बनाया जाता है (react, react-dom, और आगे भी)
  • ज़रूरत के मुताबिक, शेयर किए गए कई हिस्से बना दिए जाते हैं (ज़्यादा से ज़्यादा 25)
  • किसी डेटा का कम से कम साइज़ बदलकर 20 केबी किया जाना चाहिए

कई हिस्सों में बांटी गई इस रणनीति के ये फ़ायदे हैं:

  • पेज लोड होने के समय में सुधार किया गया है. डेटा के एक हिस्से के बजाय, शेयर किए गए कई हिस्सों को छोड़कर, किसी भी एंट्रीपॉइंट के लिए ग़ैर-ज़रूरी (या डुप्लीकेट) कोड को कम कर देता है.
  • नेविगेशन के दौरान बेहतर कैश मेमोरी. बड़ी लाइब्रेरी और फ़्रेमवर्क डिपेंडेंसी को अलग-अलग करना डेटा को अलग-अलग हिस्सों में बांट देने से, कैश मेमोरी के अमान्य होने की संभावना कम हो जाती है, क्योंकि इन दोनों में से अपग्रेड करने तक किसी भी समय बदल सकते हैं.

Next.js को webpack-config.ts में अपनाया गया पूरा कॉन्फ़िगरेशन देखा जा सकता है.

ज़्यादा एचटीटीपी अनुरोध

SplitChunksPlugin ने बारीकी से चंकने की वजह बताई. साथ ही, इस तरीके को Next.js जैसा फ़्रेमवर्क कोई नया कॉन्सेप्ट नहीं था. हालांकि, इसके बाद भी कई फ़्रेमवर्क ने एक ही अनुभव और "कॉमन्स" का इस्तेमाल करें बंडल रणनीति बनाने में कुछ दिक्कतें आ रही हैं. इसमें यह चिंता शामिल है कि बहुत से HTTP अनुरोध, साइट की परफ़ॉर्मेंस पर बुरा असर डाल सकते हैं.

ब्राउज़र किसी एक ऑरिजिन पर कुछ ही टीसीपी कनेक्शन (Chrome के लिए 6) खोल सकते हैं, इसलिए बंडलर के मिलने वाले हिस्सों की संख्या को कम करने से, यह पक्का हो सकेगा कि अनुरोधों की कुल संख्या इस थ्रेशोल्ड के तहत रहता है. हालांकि, यह सिर्फ़ एचटीटीपी/1.1 के लिए सही है. एचटीटीपी/2 में मल्टीप्लेक्सिंग एक ही कनेक्शन का इस्तेमाल करके एक से ज़्यादा अनुरोधों को साथ-साथ स्ट्रीम करने की अनुमति देता है ऑरिजिन. दूसरे शब्दों में कहें, तो हमें आम तौर पर सेगमेंट की संख्या को सीमित करने की ज़रूरत नहीं है हमारे बंडलर से उत्सर्जित किया जाता है.

सभी मुख्य ब्राउज़र, एचटीटीपी/2 के साथ काम करते हैं. Chrome और Next.js टीम देखना चाहते थे कि Next.js के सिंगल "commons" को बांटकर अनुरोधों की संख्या बढ़ रही है या नहीं समूह डेटा को कई हिस्सों में बांटकर, लोड होने की परफ़ॉर्मेंस पर असर पड़ सकता है. उन्होंने समानांतर अनुरोधों की अधिकतम संख्या को संशोधित करते हुए किसी एक साइट का प्रदर्शन maxInitialRequests प्रॉपर्टी.

अनुरोधों की संख्या में बढ़ोतरी के साथ पेज लोड की परफ़ॉर्मेंस

एक ही वेब पृष्ठ पर अनेक परीक्षणों के औसतन तीन बार आने पर, load start-render शुरुआती लेवल में बदलाव करने पर, फ़र्स्ट कॉन्टेंटफ़ुल पेंट के लेवल में कोई बदलाव नहीं हुआ अनुरोधों की संख्या (5 से 15 तक). दिलचस्प बात यह है कि हमें सिर्फ़ परफ़ॉर्मेंस से जुड़े ओवरहेड का पता चला जो सैकड़ों अनुरोधों को अलग-अलग हिस्सों में बांट दी गई.

सैकड़ों अनुरोधों के साथ पेज लोड की परफ़ॉर्मेंस

इससे पता चला कि किसी भरोसेमंद थ्रेशोल्ड (20~25 अनुरोध) के अंदर रहने पर, सही बैलेंस लोडिंग परफ़ॉर्मेंस और कैश मेमोरी में सेव होने की क्षमता के बीच का अंतर. कुछ बेसलाइन टेस्टिंग के बाद, 25 को इस रूप में चुना गया maxInitialRequest की गिनती.

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

बढ़ते चंकिंग के साथ JavaScript पेलोड में कमी

यह प्रयोग केवल अनुरोधों की संख्या को संशोधित करने के बारे में था, ताकि यह देखा जा सके कि पेज लोड परफ़ॉर्मेंस पर बुरा असर पड़ता है. नतीजों का सुझाव है कि maxInitialRequests को इस पर सेट करें जांच वाले पेज पर 25 सबसे अच्छा था, क्योंकि इसने धीमा किए बिना JavaScript पेलोड का साइज़ कम कर दिया डालें. पेज को हाइड्रेट करने के लिए ज़रूरी JavaScript की कुल मात्रा अब भी बनी हुई है करीब-करीब एक जैसा है. यह बताता है कि पेज लोड होने की परफ़ॉर्मेंस में सुधार होने के बावजूद कोड की मात्रा.

वेबपैक जनरेट करने के लिए, डिफ़ॉल्ट तौर पर कम से कम 30 केबी का साइज़ इस्तेमाल करता है. हालांकि, एक जोड़ी कम से कम 20 केबी साइज़ वाली maxInitialRequests वैल्यू 25 के बजाय बेहतर कैश मेमोरी में सेव होती है.

बारीक हिस्सों के साथ साइज़ छोटा करने वाले टूल

Next.js के साथ-साथ कई फ़्रेमवर्क, इंजेक्ट करने के लिए क्लाइंट-साइड रूटिंग (JavaScript की मदद से मैनेज किए जाने वाले) का इस्तेमाल करते हैं हर रूट के ट्रांज़िशन के लिए नए स्क्रिप्ट टैग जोड़े जा सकते हैं. हालांकि, बिल्ड बनाते समय वे इन डाइनैमिक हिस्सों को पहले से कैसे तय करते हैं?

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/ -238 केबी -23%
https://sumup.com/ -220 केबी -30% से कम
https://www.hashicorp.com/ -11 एमबी -71% से कम
JavaScript के साइज़ में कमी - सभी रूट पर (कंप्रेस की गई)

फ़ाइनल वर्शन, वर्शन 9.2 के लिए डिफ़ॉल्ट रूप से शिप किया गया था.

गैट्सबी

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)[\\/]/,
      },

इसके लिए, अपने Webpack कॉन्फ़िगरेशन को ऑप्टिमाइज़ करके, तेज़ी से डेटा को कम करने की ऐसी ही रणनीति अपनाई जा सकती है. कई बड़ी साइटों में JavaScript में बड़े पैमाने पर गिरावट देखी गई:

वेबसाइट कुल JS में बदलाव % का अंतर
https://www.gatsbyjs.org/ -680 केबी -22%
https://www.thirdandgrove.com/ -390 केबी -25%
https://ghost.org/ -1.1 एमबी -35% से कम
https://reactjs.org/ -80 केबी -8%
JavaScript के साइज़ में कमी - सभी रूट पर (कंप्रेस की गई)

पीआर पर एक नज़र डालें और जानें कि उन्हें किस तरह इस लॉजिक को अपने Webpack कॉन्फ़िगरेशन में लागू किया है, जो कि 2.20.7 वर्शन में डिफ़ॉल्ट रूप से शिप किया जाता है.

नतीजा

विस्तृत समूह की शिपिंग का सिद्धांत Next.js, Gatsby या यहां तक कि webpack के लिए भी नहीं है. सभी के लिए उपलब्ध को अपने ऐप्लिकेशन की ऐसी रणनीति को बेहतर बनाने पर विचार करना चाहिए जो "कॉमन" का पालन करता हो बंडल वाला तरीका इस्तेमाल किया जा सकता है. भले ही, किसी भी फ़्रेमवर्क या मॉड्यूल बंडलर का इस्तेमाल किया गया हो.

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