लंबे समय तक कैश मेमोरी में सेव करने की सुविधा का इस्तेमाल करना

वेबपैक, ऐसेट को कैश मेमोरी में सेव करने में कैसे मदद करता है

ऐप्लिकेशन के साइज़ को ऑप्टिमाइज़ करने के बाद, ऐप्लिकेशन लोड होने में लगने वाले समय को कम करने के लिए, कैश मेमोरी का इस्तेमाल किया जा सकता है. इसका इस्तेमाल करके, ऐप्लिकेशन के कुछ हिस्सों को क्लाइंट पर सेव किया जा सकता है. इससे, उन्हें हर बार फिर से डाउनलोड करने की ज़रूरत नहीं पड़ती.

बंडल वर्शन और कैश मेमोरी हेडर का इस्तेमाल करना

कैश मेमोरी का इस्तेमाल करने का सामान्य तरीका यह है:

  1. ब्राउज़र को किसी फ़ाइल को बहुत लंबे समय (जैसे, एक साल) के लिए कैश मेमोरी में सेव करने के लिए कहें:

    # Server header
    Cache-Control: max-age=31536000
    

    अगर आपको नहीं पता कि Cache-Control क्या करता है, तो कैश मेमोरी का इस्तेमाल करने के सबसे सही तरीकों के बारे में, जैक आर्किबाल्ड की बेहतरीन पोस्ट देखें.

  2. और फ़ाइल में बदलाव होने पर, उसका नाम बदलकर उसे फिर से डाउनलोड करें:

    <!-- Before the change -->
    <script src="./index-v15.js"></script>
    
    <!-- After the change -->
    <script src="./index-v16.js"></script>
    

इस तरीके से, ब्राउज़र को JS फ़ाइल डाउनलोड करने, उसे कैश मेमोरी में सेव करने, और कैश मेमोरी में सेव की गई कॉपी का इस्तेमाल करने के लिए कहा जाता है. ब्राउज़र सिर्फ़ तब नेटवर्क से कनेक्ट होगा, जब फ़ाइल का नाम बदला जाएगा (या एक साल बीत जाएगा).

webpack में भी यही तरीका अपनाया जाता है. हालांकि, वर्शन नंबर के बजाय, फ़ाइल हैश का इस्तेमाल किया जाता है. फ़ाइल के नाम में हैश शामिल करने के लिए, [chunkhash] का इस्तेमाल करें:

// webpack.config.js
module.exports = {
  entry: './index.js',
  output: {
    filename: 'bundle.[chunkhash].js' // → bundle.8e0d62a03.js
  }
};

अगर आपको क्लाइंट को फ़ाइल का नाम भेजना है, तो HtmlWebpackPlugin या WebpackManifestPlugin में से किसी एक का इस्तेमाल करें.

HtmlWebpackPlugin एक आसान तरीका है, लेकिन इसमें ज़्यादा विकल्प नहीं होते. कंपाइल करने के दौरान, यह प्लग इन एक एचटीएमएल फ़ाइल जनरेट करता है. इसमें कंपाइल किए गए सभी रिसॉर्स शामिल होते हैं. अगर आपके सर्वर लॉजिक में कोई मुश्किल बात नहीं है, तो यह तरीका आपके लिए काफ़ी होगा:

<!-- index.html -->
<!DOCTYPE html>
<!-- ... -->
<script src="bundle.8e0d62a03.js"></script>

WebpackManifestPlugin एक ज़्यादा सुविधाजनक तरीका है. यह तब काम आता है, जब आपके पास सर्वर का जटिल हिस्सा हो. बिल्ड के दौरान, यह हैश के बिना फ़ाइल के नामों और हैश के साथ फ़ाइल के नामों के बीच मैपिंग वाली एक JSON फ़ाइल जनरेट करती है. सर्वर पर इस JSON का इस्तेमाल करके पता लगाएं कि किस फ़ाइल के साथ काम करना है:

// manifest.json
{
  "bundle.js": "bundle.8e0d62a03.js"
}

इसके बारे में और पढ़ें

डिपेंडेंसी और रनटाइम को अलग फ़ाइल में निकालना

डिपेंडेंसी

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

डिपेंडेंसी को अलग-अलग चंक में निकालने के लिए, ये तीन चरण पूरे करें:

  1. आउटपुट फ़ाइल का नाम [name].[chunkname].js से बदलें:

    // webpack.config.js
    module.exports = {
      output: {
        // Before
        filename: 'bundle.[chunkhash].js',
        // After
        filename: '[name].[chunkhash].js'
      }
    };
    

    जब webpack ऐप्लिकेशन बनाता है, तो वह [name] को किसी चंक के नाम से बदल देता है. अगर हम [name] वाला हिस्सा नहीं जोड़ते हैं, तो हमें चंकों के हैश के आधार पर उनके बीच अंतर करना होगा – जो काफ़ी मुश्किल है!

  2. entry फ़ील्ड को ऑब्जेक्ट में बदलें:

    // webpack.config.js
    module.exports = {
      // Before
      entry: './index.js',
      // After
      entry: {
        main: './index.js'
      }
    };
    

    इस स्निपेट में, "main" एक चंक का नाम है. इस नाम को पहले चरण में मौजूद [name] की जगह पर डाला जाएगा.

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

  3. webpack 4 में, अपने webpack कॉन्फ़िगरेशन में optimization.splitChunks.chunks: 'all' विकल्प जोड़ें:

    // webpack.config.js (for webpack 4)
    module.exports = {
      optimization: {
        splitChunks: {
          chunks: 'all'
        }
      }
    };
    

    यह विकल्प, स्मार्ट कोड स्प्लिटिंग की सुविधा चालू करता है. इसकी मदद से, वेंडर कोड को तब निकाला जाएगा, जब वह कम करने और gzip करने से पहले 30 केबी से ज़्यादा हो जाएगा. यह सामान्य कोड भी निकालेगा – यह तब काम आता है, जब आपके बिल्ड से कई बंडल बनते हैं. उदाहरण के लिए, अगर आपने अपने ऐप्लिकेशन को रास्तों में बांटा है.

    webpack 3 में, CommonsChunkPlugin जोड़ें:

    // webpack.config.js (for webpack 3)
    module.exports = {
      plugins: [
        new webpack.optimize.CommonsChunkPlugin({
        // A name of the chunk that will include the dependencies.
        // This name is substituted in place of [name] from step 1
        name: 'vendor',
    
        // A function that determines which modules to include into this chunk
        minChunks: module => module.context && module.context.includes('node_modules'),
        })
      ]
    };
    

    यह प्लग इन उन सभी मॉड्यूल को लेता है जिनके पाथ में node_modules शामिल होता है और उन्हें vendor.[chunkhash].js नाम की अलग फ़ाइल में ले जाता है.

इन बदलावों के बाद, हर बिल्ड एक के बजाय दो फ़ाइलें जनरेट करेगा: main.[chunkhash].js और vendor.[chunkhash].js (webpack 4 के लिए vendors~main.[chunkhash].js). webpack 4 के मामले में, अगर डिपेंडेंसी कम हैं, तो हो सकता है कि वेंडर बंडल जनरेट न हो – और यह ठीक है:

$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
                        Asset      Size  Chunks             Chunk Names
 ./main.00bab6fd3100008a42b0.js   82 kB       0  [emitted]  main
./vendor.d9e134771799ecdf9483.js  47 kB       1  [emitted]  vendor

ब्राउज़र इन फ़ाइलों को अलग से कैश मेमोरी में सेव करेगा. साथ ही, सिर्फ़ बदले गए कोड को फिर से डाउनलोड करेगा.

Webpack रनटाइम कोड

माफ़ करें, सिर्फ़ वेंडर कोड निकालना काफ़ी नहीं है. अगर ऐप्लिकेशन कोड में कुछ बदलने की कोशिश की जाती है, तो:

// index.js
…
…

// E.g. add this:
console.log('Wat');

आपको दिखेगा कि vendor हैश भी बदल गया है:

                           Asset   Size  Chunks             Chunk Names
./vendor.d9e134771799ecdf9483.js  47 kB       1  [emitted]  vendor

                            Asset   Size  Chunks             Chunk Names
./vendor.e6ea4504d61a1cc1c60b.js  47 kB       1  [emitted]  vendor

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

// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
    "0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";

Webpack, इस रनटाइम को आखिरी जनरेट किए गए चंक में शामिल करता है. हमारे मामले में, यह vendor है. जब भी कोई चंक बदलता है, तो यह कोड भी बदल जाता है. इससे पूरा vendor चंक बदल जाता है.

इस समस्या को हल करने के लिए, रनटाइम को किसी अलग फ़ाइल में ले चलते हैं. webpack 4 में, optimization.runtimeChunk विकल्प को चालू करके ऐसा किया जा सकता है:

// webpack.config.js (for webpack 4)
module.exports = {
  optimization: {
    runtimeChunk: true
  }
};

webpack 3 में, CommonsChunkPlugin की मदद से एक अतिरिक्त खाली चंक बनाकर ऐसा करें:

// webpack.config.js (for webpack 3)
module.exports = {
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: module => module.context && module.context.includes('node_modules')
    }),
    // This plugin must come after the vendor one (because webpack
    // includes runtime into the last chunk)
    new webpack.optimize.CommonsChunkPlugin({
      name: 'runtime',
      // minChunks: Infinity means that no app modules
      // will be included into this chunk
      minChunks: Infinity
    })
  ]
};

इन बदलावों के बाद, हर बिल्ड से तीन फ़ाइलें जनरेट होंगी:

$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
                            Asset     Size  Chunks             Chunk Names
   ./main.00bab6fd3100008a42b0.js    82 kB       0  [emitted]  main
 ./vendor.26886caf15818fa82dfa.js    46 kB       1  [emitted]  vendor
./runtime.79f17c27b335abc7aaf4.js  1.45 kB       3  [emitted]  runtime

उन्हें उलटे क्रम में index.html में शामिल करें – और हो गया:

<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>
<script src="./vendor.26886caf15818fa82dfa.js"></script>
<script src="./main.00bab6fd3100008a42b0.js"></script>

इसके बारे में और पढ़ें

अतिरिक्त एचटीटीपी अनुरोध को सेव करने के लिए, इनलाइन वेबपैक रनटाइम

इसे और बेहतर बनाने के लिए, वेबपैक रनटाइम को एचटीएमएल रिस्पॉन्स में इनलाइन करने की कोशिश करें. जैसे, इसके बजाय:

<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>

ऐसा करें:

<!-- index.html -->
<script>
!function(e){function n(r){if(t[r])return t[r].exports;…}} ([]);
</script>

रनटाइम कम है और इसे इनलाइन करने से, आपको एचटीटीपी अनुरोध को सेव करने में मदद मिलेगी. यह एचटीटीपी/1 के लिए काफ़ी ज़रूरी है. हालांकि, एचटीटीपी/2 के लिए ज़रूरी नहीं है, लेकिन फिर भी इसका असर पड़ सकता है.

इसका तरीका यहां बताया गया है.

अगर HtmlWebpackPlugin की मदद से एचटीएमएल जनरेट किया जाता है, तो

अगर एचटीएमएल फ़ाइल जनरेट करने के लिए, HtmlWebpackPlugin का इस्तेमाल किया जाता है, तो आपको सिर्फ़ InlineSourcePlugin की ज़रूरत होगी:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineSourcePlugin = require('html-webpack-inline-source-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      inlineSource: 'runtime~.+\\.js',
    }),
    new InlineSourcePlugin()
  ]
};

अगर कस्टम सर्वर लॉजिक का इस्तेमाल करके एचटीएमएल जनरेट किया जाता है

webpack 4 के साथ:

  1. रनटाइम चंक का जनरेट किया गया नाम जानने के लिए, WebpackManifestPlugin जोड़ें:

    // webpack.config.js (for webpack 4)
    const ManifestPlugin = require('webpack-manifest-plugin');
    
    module.exports = {
      plugins: [
        new ManifestPlugin()
      ]
    };
    

    इस प्लग इन की मदद से बनाए गए बिल्ड से, ऐसी फ़ाइल बनेगी जो कुछ इस तरह दिखेगी:

    // manifest.json
    {
      "runtime~main.js": "runtime~main.8e0d62a03.js"
    }
    
  2. रनटाइम चंक के कॉन्टेंट को आसानी से इनलाइन करें. उदाहरण के लिए, Node.js और Express के साथ:

    // server.js
    const fs = require('fs');
    const manifest = require('./manifest.json');
    const runtimeContent = fs.readFileSync(manifest['runtime~main.js'], 'utf-8');
    
    app.get('/', (req, res) => {
      res.send(`
        …
        <script>${runtimeContent}</script>
        …
      `);
    });
    

या webpack 3 के साथ:

  1. filename की वैल्यू डालकर, रनटाइम का नाम स्टैटिक बनाएं:

    module.exports = {
      plugins: [
        new webpack.optimize.CommonsChunkPlugin({
          name: 'runtime',
          minChunks: Infinity,
          filename: 'runtime.js'
        })
      ]
    };
    
  2. runtime.js कॉन्टेंट को आसानी से इनलाइन करें. उदाहरण के लिए, Node.js और Express के साथ:

    // server.js
    const fs = require('fs');
    const runtimeContent = fs.readFileSync('./runtime.js', 'utf-8');
    
    app.get('/', (req, res) => {
      res.send(`
        …
        <script>${runtimeContent}</script>
        …
      `);
    });
    

ऐसा लेज़ी-लोड कोड जिसकी आपको अभी ज़रूरत नहीं है

कभी-कभी, किसी पेज के कुछ हिस्से ज़्यादा अहम होते हैं और कुछ कम:

  • YouTube पर किसी वीडियो का पेज लोड करने पर, दर्शकों को टिप्पणियों से ज़्यादा वीडियो में दिलचस्पी होती है. यहां वीडियो, टिप्पणियों से ज़्यादा अहम है.
  • अगर किसी समाचार साइट पर कोई लेख खोला जाता है, तो आपको विज्ञापनों के मुकाबले लेख के टेक्स्ट पर ज़्यादा ध्यान रहता है. यहां टेक्स्ट, विज्ञापनों से ज़्यादा अहम होता है.

ऐसे मामलों में, सबसे ज़रूरी कॉन्टेंट को पहले डाउनलोड करके, शुरुआती लोडिंग की परफ़ॉर्मेंस को बेहतर बनाएं. इसके बाद, बाकी कॉन्टेंट को धीरे-धीरे लोड करें. इसके लिए, import() फ़ंक्शन और कोड-स्प्लिटिंग का इस्तेमाल करें:

// videoPlayer.js
export function renderVideoPlayer() { … }

// comments.js
export function renderComments() { … }

// index.js
import {renderVideoPlayer} from './videoPlayer';
renderVideoPlayer();

// …Custom event listener
onShowCommentsClick(() => {
  import('./comments').then((comments) => {
    comments.renderComments();
  });
});

import() से पता चलता है कि आपको किसी खास मॉड्यूल को डाइनैमिक तौर पर लोड करना है. जब webpack को import('./module.js') दिखता है, तो वह इस मॉड्यूल को एक अलग चंक में ले जाता है:

$ webpack
Hash: 39b2a53cb4e73f0dc5b2
Version: webpack 3.8.1
Time: 4273ms
                            Asset     Size  Chunks             Chunk Names
      ./0.8ecaf182f5c85b7a8199.js  22.5 kB       0  [emitted]
   ./main.f7e53d8e13e9a2745d6d.js    60 kB       1  [emitted]  main
 ./vendor.4f14b6326a80f4752a98.js    46 kB       2  [emitted]  vendor
./runtime.79f17c27b335abc7aaf4.js  1.45 kB       3  [emitted]  runtime

और इसे सिर्फ़ तब डाउनलोड करता है, जब एक्सेक्यूशन import() फ़ंक्शन तक पहुंचता है.

इससे main बंडल छोटा हो जाएगा और शुरुआती लोडिंग में लगने वाला समय कम हो जाएगा. इससे कैश मेमोरी में सेव करने की प्रोसेस भी बेहतर होगी – अगर मुख्य चंक में कोड बदला जाता है, तो टिप्पणियों के चंक पर इसका असर नहीं पड़ेगा.

इसके बारे में और पढ़ें

कोड को रूट और पेजों में बांटना

अगर आपके ऐप्लिकेशन में कई रूट या पेज हैं, लेकिन कोड (एक main चंक) वाली सिर्फ़ एक JS फ़ाइल है, तो हो सकता है कि आप हर अनुरोध पर अतिरिक्त बाइट भेज रहे हों. उदाहरण के लिए, जब कोई उपयोगकर्ता आपकी साइट के होम पेज पर जाता है, तो:

WebFundamentals का होम पेज

उन्हें किसी दूसरे पेज पर मौजूद लेख को रेंडर करने के लिए, कोड लोड करने की ज़रूरत नहीं होती – हालांकि, वे इसे लोड करेंगे. इसके अलावा, अगर उपयोगकर्ता हमेशा सिर्फ़ होम पेज पर जाता है और आपने लेख के कोड में बदलाव किया है, तो वेबपैक पूरे बंडल को अमान्य कर देगा. साथ ही, उपयोगकर्ता को पूरा ऐप्लिकेशन फिर से डाउनलोड करना होगा.

अगर हम ऐप्लिकेशन को पेजों (या अगर यह एक पेज वाला ऐप्लिकेशन है, तो रास्तों) में बांटते हैं, तो उपयोगकर्ता सिर्फ़ काम का कोड डाउनलोड करेगा. साथ ही, ब्राउज़र ऐप्लिकेशन कोड को बेहतर तरीके से कैश मेमोरी में सेव करेगा: अगर होम पेज के कोड में बदलाव किया जाता है, तो वेबपैक सिर्फ़ उससे जुड़े चंक को अमान्य कर देगा.

एक पेज वाले ऐप्लिकेशन के लिए

सिंगल-पेज ऐप्लिकेशन को रास्तों के हिसाब से बांटने के लिए, import() का इस्तेमाल करें. इसके लिए, “ऐसा लैज़ी-लोड कोड जो फ़िलहाल आपके काम का नहीं है” सेक्शन देखें. अगर किसी फ़्रेमवर्क का इस्तेमाल किया जाता है, तो हो सकता है कि उसमें इस समस्या का हल पहले से मौजूद हो:

कई पेजों वाले पारंपरिक ऐप्लिकेशन के लिए

पारंपरिक ऐप्लिकेशन को पेजों के हिसाब से बांटने के लिए, webpack के एंट्री पॉइंट का इस्तेमाल करें. अगर आपके ऐप्लिकेशन में तीन तरह के पेज हैं: होम पेज, लेख पेज, और उपयोगकर्ता खाता पेज, तो इसमें तीन एंट्री होनी चाहिए:

// webpack.config.js
module.exports = {
  entry: {
    home: './src/Home/index.js',
    article: './src/Article/index.js',
    profile: './src/Profile/index.js'
  }
};

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

$ webpack
Hash: 318d7b8490a7382bf23b
Version: webpack 3.8.1
Time: 4273ms
                            Asset     Size  Chunks             Chunk Names
      ./0.8ecaf182f5c85b7a8199.js  22.5 kB       0  [emitted]
   ./home.91b9ed27366fe7e33d6a.js    18 kB       1  [emitted]  home
./article.87a128755b16ac3294fd.js    32 kB       2  [emitted]  article
./profile.de945dc02685f6166781.js    24 kB       3  [emitted]  profile
 ./vendor.4f14b6326a80f4752a98.js    46 kB       4  [emitted]  vendor
./runtime.318d7b8490a7382bf23b.js  1.45 kB       5  [emitted]  runtime

इसलिए, अगर सिर्फ़ लेख वाले पेज पर Lodash का इस्तेमाल किया जाता है, तो home और profile बंडल में इसे शामिल नहीं किया जाएगा. साथ ही, होम पेज पर जाने पर उपयोगकर्ता को यह लाइब्रेरी डाउनलोड नहीं करनी पड़ेगी.

हालांकि, अलग-अलग डिपेंडेंसी ट्री में कुछ समस्याएं होती हैं. अगर दो एंट्री पॉइंट, Lodash का इस्तेमाल करते हैं और आपने अपनी डिपेंडेंसी को वेंडर बंडल में नहीं भेजा है, तो दोनों एंट्री पॉइंट में Lodash की एक कॉपी शामिल होगी. इस समस्या को हल करने के लिए, webpack 4 में, अपने webpack कॉन्फ़िगरेशन में optimization.splitChunks.chunks: 'all' विकल्प जोड़ें:

// webpack.config.js (for webpack 4)
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
};

यह विकल्प, स्मार्ट कोड स्प्लिटिंग की सुविधा चालू करता है. इस विकल्प की मदद से, webpack अपने-आप सामान्य कोड ढूंढेगा और उसे अलग-अलग फ़ाइलों में निकाल देगा.

इसके अलावा, webpack 3 में CommonsChunkPlugin का इस्तेमाल करें. इससे,सामान्य डिपेंडेंसी को किसी नई फ़ाइल में ले जाया जाएगा:

module.exports = {
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'common',
      minChunks: 2    // 2 is the default value
    })
  ]
};

सबसे अच्छी वैल्यू ढूंढने के लिए, minChunks वैल्यू में बदलाव करें. आम तौर पर, इसे छोटा रखना चाहिए. हालांकि, अगर चंक की संख्या बढ़ती है, तो इसे बढ़ाया जा सकता है. उदाहरण के लिए, तीन चंक के लिए minChunks की वैल्यू 2 हो सकती है, लेकिन 30 चंक के लिए यह 8 हो सकती है. ऐसा इसलिए, क्योंकि अगर आपने इसे दो पर सेट किया है, तो सामान्य फ़ाइल में बहुत ज़्यादा मॉड्यूल शामिल हो जाएंगे और फ़ाइल का साइज़ बहुत ज़्यादा बढ़ जाएगा.

इसके बारे में और पढ़ें

मॉड्यूल आईडी को ज़्यादा स्थिर बनाना

कोड बनाते समय, webpack हर मॉड्यूल को एक आईडी असाइन करता है. बाद में, इन आईडी का इस्तेमाल, बंडल में मौजूद require() में किया जाता है. आम तौर पर, आपको मॉड्यूल पाथ के ठीक पहले, बिल्ड आउटपुट में आईडी दिखते हैं:

$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
                           Asset      Size  Chunks             Chunk Names
      ./0.8ecaf182f5c85b7a8199.js  22.5 kB       0  [emitted]
   ./main.4e50a16675574df6a9e9.js    60 kB       1  [emitted]  main
 ./vendor.26886caf15818fa82dfa.js    46 kB       2  [emitted]  vendor
./runtime.79f17c27b335abc7aaf4.js  1.45 kB       3  [emitted]  runtime

↓ यहां

[0] ./index.js 29 kB {1} [built]
[2] (webpack)/buildin/global.js 488 bytes {2} [built]
[3] (webpack)/buildin/module.js 495 bytes {2} [built]
[4] ./comments.js 58 kB {0} [built]
[5] ./ads.js 74 kB {1} [built]
+ 1 hidden module

डिफ़ॉल्ट रूप से, आईडी की गिनती काउंटर का इस्तेमाल करके की जाती है. जैसे, पहले मॉड्यूल का आईडी 0, दूसरे मॉड्यूल का आईडी 1 वगैरह. इसकी समस्या यह है कि जब कोई नया मॉड्यूल जोड़ा जाता है, तो हो सकता है कि वह मॉड्यूल की सूची के बीच में दिखे. इससे, अगले सभी मॉड्यूल के आईडी बदल जाते हैं:

$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
                           Asset      Size  Chunks             Chunk Names
      ./0.5c82c0f337fcb22672b5.js    22 kB       0  [emitted]
   ./main.0c8b617dfc40c2827ae3.js    82 kB       1  [emitted]  main
 ./vendor.26886caf15818fa82dfa.js    46 kB       2  [emitted]  vendor
./runtime.79f17c27b335abc7aaf4.js  1.45 kB       3  [emitted]  runtime
   [0] ./index.js 29 kB {1} [built]
   [2] (webpack)/buildin/global.js 488 bytes {2} [built]
   [3] (webpack)/buildin/module.js 495 bytes {2} [built]

↓ हमने एक नया मॉड्यूल जोड़ा है…

[4] ./webPlayer.js 24 kB {1} [built]

↓ और देखें कि इसने क्या किया है! comments.js के पास अब आईडी 4 के बजाय 5 है

[5] ./comments.js 58 kB {0} [built]

ads.js का आईडी, 5 के बजाय अब 6 हो गया है

[6] ./ads.js 74 kB {1} [built]
       + 1 hidden module

इससे उन सभी चंक अमान्य हो जाते हैं जिनमें बदले गए आईडी वाले मॉड्यूल शामिल होते हैं या जिन पर उन मॉड्यूल का इस्तेमाल होता है. भले ही, उनका असल कोड न बदला गया हो. हमारे मामले में, 0 चंक (comments.js वाला चंक) और main चंक (अन्य ऐप्लिकेशन कोड वाला चंक) अमान्य हो जाता है – जबकि सिर्फ़ main चंक को अमान्य किया जाना चाहिए था.

इस समस्या को हल करने के लिए, HashedModuleIdsPlugin का इस्तेमाल करके, मॉड्यूल आईडी का हिसाब लगाने का तरीका बदलें. यह काउंटर पर आधारित आईडी को मॉड्यूल पाथ के हैश से बदल देता है:

$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
                           Asset      Size  Chunks             Chunk Names
      ./0.6168aaac8461862eab7a.js  22.5 kB       0  [emitted]
   ./main.a2e49a279552980e3b91.js    60 kB       1  [emitted]  main
 ./vendor.ff9f7ea865884e6a84c8.js    46 kB       2  [emitted]  vendor
./runtime.25f5d0204e4f77fa57a1.js  1.45 kB       3  [emitted]  runtime

↓ यहां

[3IRH] ./index.js 29 kB {1} [built]
[DuR2] (webpack)/buildin/global.js 488 bytes {2} [built]
[JkW7] (webpack)/buildin/module.js 495 bytes {2} [built]
[LbCc] ./webPlayer.js 24 kB {1} [built]
[lebJ] ./comments.js 58 kB {0} [built]
[02Tr] ./ads.js 74 kB {1} [built]
    + 1 hidden module

इस तरीके से, किसी मॉड्यूल का आईडी सिर्फ़ तब बदलता है, जब उसका नाम बदला जाता है या उसे एक से दूसरी जगह ले जाया जाता है. नए मॉड्यूल से, दूसरे मॉड्यूल के आईडी पर कोई असर नहीं पड़ेगा.

प्लग इन को चालू करने के लिए, उसे कॉन्फ़िगरेशन के plugins सेक्शन में जोड़ें:

// webpack.config.js
module.exports = {
  plugins: [
    new webpack.HashedModuleIdsPlugin()
  ]
};

इसके बारे में और पढ़ें

खास जानकारी

  • बंडल को कैश मेमोरी में सेव करना और बंडल के नाम को बदलकर, वर्शन के बीच अंतर करना
  • बंडल को ऐप्लिकेशन कोड, वेंडर कोड, और रनटाइम में बांटना
  • एचटीटीपी अनुरोध को सेव करने के लिए, रनटाइम को इनलाइन करना
  • import का इस्तेमाल करके, ज़रूरी न होने वाले कोड को धीरे-धीरे लोड करना
  • गै़र-ज़रूरी कॉन्टेंट लोड होने से बचने के लिए, कोड को रूट/पेजों के हिसाब से बांटें