الاستفادة من التخزين المؤقّت الطويل المدى

كيفية مساعدة webpack في ميزة تخزين مواد العرض مؤقتًا

بعد تحسين حجم التطبيق، يمكن تحسين وقت تحميل التطبيق من خلال ميزة التخزين المؤقت. يمكنك استخدامها للحفاظ على أجزاء من التطبيق على العميل وتجنُّب إعادة تنزيلها في كل مرة.

استخدام عناوين ذاكرة التخزين المؤقت وإصدار الحِزمة

الطريقة الشائعة للتخزين المؤقت هي:

  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 هو نهج بسيط، ولكنه أقل مرونة. أثناء عملية الترجمة، ينشئ هذا المكوّن الإضافي ملف HTML يتضمّن جميع الموارد المجمّعة. إذا لم يكن منطق الخادم معقدًا، من المفترض أن يكون كافيًا لك:

<!-- 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] من الخطوة 1.

    في الوقت الحالي، إذا أنشأت التطبيق، سيتضمّن هذا الجزء رمز التطبيق بالكامل، تمامًا كما لو لم ننفِّذ هذه الخطوات. ولكن سيتم تغيير ذلك بعد ثانية.

  3. في webpack 4، أضِف الخيار optimization.splitChunks.chunks: 'all' إلى إعدادات webpack:

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

    يُفعِّل هذا الخيار ميزة "تقسيم الرموز الذكية". باستخدام هذه الميزة، ستستخرج أداة webpack رمز المورّد إذا زاد حجمه عن 30 كيلوبايت (قبل التصغير واستخدام gzip). ستستخرج الأداة أيضًا الرمز المشترَك، وهو أمر مفيد إذا كان الإصدار ينتج عدة حِزم (مثل في حال تقسيم تطبيقك إلى مسارات).

    في 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 (vendors~main.[chunkhash].js لواجهة webpack 4). في حالة استخدام 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

ويحدث ذلك لأنّ حِزمة webpack، بالإضافة إلى رمز الوحدات، تتضمّن مرحلت تنفيذ، وهي عبارة عن قطعة صغيرة من الرمز المبرمَج تدير تنفيذ الوحدة. عند تقسيم الرمز البرمجي إلى ملفات متعددة، تبدأ هذه القطعة من الرمز البرمجي في تضمين تعيين بين أرقام تعريف المقاطع والملفّات المقابلة:

// 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>

محتوى إضافي للقراءة

بيئة تشغيل حزمة الويب المضمّنة لحفظ طلب HTTP إضافي

لتحسين الأداء، جرِّب تضمين وقت تشغيل webpack في ملف HTML المستلَم. أي بدلاً من هذا:

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

اتّبِع الخطوات التالية:

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

وقت التشغيل صغير، وستساعدك تضمينها فيه في حفظ طلب HTTP (وهو مهم جدًا في HTTP/1، وهو أقل أهمية مع HTTP/2 ولكن قد يبقى له تأثير).

إليك كيفية إجراء ذلك.

في حال إنشاء صفحات HTML باستخدام HtmlWebpackPlugin

إذا كنت تستخدم HtmlWebpackPlugin لإنشاء ملف HTML، كل ما تحتاجه هو 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()
  ]
};

إذا كنت تنشئ صفحات HTML باستخدام منطق خادم مخصّص

مع 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، ما يُحسِّن من وقت التحميل الأوّلي. بالإضافة إلى ذلك، سيؤدي ذلك إلى تحسين التخزين المؤقت. فإذا غيّرت الرمز في الجزء الرئيسي، لن يتأثّر ملف التعليقات.

مراجع إضافية

تقسيم الرمز إلى مسارات وصفحات

إذا كان تطبيقك يتضمّن عدة مسارات أو صفحات، ولكن لا يتضمّن سوى ملف JS واحد يحتوي على الرمز (جزء واحد من main)، من المرجّح أنك تعرض وحدات بايت إضافية في كل طلب. على سبيل المثال، عندما يزور أحد المستخدِمين الصفحة الرئيسية لموقعك الإلكتروني:

صفحة WebFundamentals الرئيسية

وليس بحاجة إلى تحميل الرمز لعرض مقالة موجودة على صفحة مختلفة، ولكن سيتم تحميلها. بالإضافة إلى ذلك، إذا كان المستخدم يزور دائمًا الصفحة الرئيسية فقط، وأجريت تغييرًا في رمز المقالة، سيبطل webpack الحزمة بأكملها، وسيضطر المستخدم إلى إعادة تنزيل التطبيق بأكمله.

إذا قسمنا التطبيق إلى صفحات (أو مسارات، إذا كان تطبيقًا مكوّنًا من صفحة واحدة)، لن ينزِّل المستخدم سوى الرمز برمجي المعني. بالإضافة إلى ذلك، سيخزّن المتصفّح رمز التطبيق مؤقتًا بشكل أفضل: إذا غيّرت رمز الصفحة الرئيسية، ستُلغي webpack المقطع المقابل فقط.

بالنسبة إلى التطبيقات المكوّنة من صفحة واحدة

لتقسيم تطبيقات الصفحة الواحدة حسب المسارات، استخدِم 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، أضِف الخيار optimization.splitChunks.chunks: 'all' إلى إعدادات webpack:

// 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 للعثور على القيمة الأفضل. بشكل عام، تريد أن تجعله صغيرًا، لكن يزداد إذا زاد عدد الأجزاء. على سبيل المثال، بالنسبة إلى 3 أجزاء، قد يكون minChunks هو 2، ولكن بالنسبة إلى 30 جزءًا، قد يكون 8 – لأنّه في حال إبقاءه على 2، ستتم إضافة عدد كبير جدًا من الوحدات إلى الملف المشترك، مما يؤدي إلى تضخيم حجمه بشكل كبير جدًا.

محتوى إضافي للقراءة

جعل أرقام تعريف الوحدات أكثر ثباتًا

عند إنشاء الرمز، يخصّص 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 الآن المعرّف 5 بدلاً من 4

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

↓ أصبح لدى ads.js الآن رقم التعريف 6 بدلاً من 5

[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()
  ]
};

محتوى إضافي للقراءة

ملخّص

  • تخزين الحِزمة مؤقتًا والتفريق بين الإصدارات من خلال تغيير اسم الحِزمة
  • تقسيم الحِزمة إلى رمز التطبيق ورمز المورّد ووقت التشغيل
  • تضمين بيئة التشغيل لحفظ طلب HTTP
  • تحميل الرمز غير المهم بشكل بطيء باستخدام import
  • تقسيم الرمز حسب المسارات أو الصفحات لتجنُّب تحميل المحتوى غير الضروري