Hot Module Replacement
تقوم ميزة Hot Module Replacement أو (HMR) بتبديل الوحدات أو إضافتها أو إزالتها أثناء تشغيل التطبيق، بدون إعادة تحميل كاملة. يمكن أن يسرّع ذلك التطوير بشكل ملحوظ بعدة طرق:
- الاحتفاظ بحالة التطبيق التي تضيع عادةً عند إعادة التحميل الكامل.
- توفير وقت تطوير ثمين عبر تحديث ما تغيّر فقط.
- تحديث المتصفح فورًا عند إجراء تعديلات على CSS/JS في الكود المصدري، وهو قريب جدًا من تعديل التنسيقات مباشرة داخل أدوات المطور في المتصفح.
كيف تعمل
لننظر إلى HMR من عدة زوايا لفهم طريقة عملها بدقة.
داخل التطبيق
تسمح الخطوات التالية بتبديل الوحدات داخل التطبيق وخارجه:
- يطلب التطبيق من HMR runtime التحقق من وجود تحديثات.
- يحمّل runtime التحديثات بشكل غير متزامن ويخطر التطبيق.
- يطلب التطبيق بعد ذلك من runtime تطبيق التحديثات.
- يطبق runtime التحديثات بشكل متزامن.
يمكنك إعداد HMR بحيث تحدث هذه العملية تلقائيًا، أو يمكنك اختيار طلب تفاعل المستخدم قبل حدوث التحديثات.
داخل المترجم
إلى جانب الأصول العادية، يحتاج المترجم إلى إصدار "تحديث" يسمح بالانتقال من الإصدار السابق إلى الإصدار الجديد. يتكون "التحديث" من جزأين:
- manifest محدث (JSON)
- واحد أو أكثر من chunks المحدثة (JavaScript)
يحتوي manifest على هاش الترجمة الجديد وقائمة بجميع chunks المحدثة. يحتوي كل chunk من هذه chunks على الكود الجديد لكل الوحدات المحدثة، أو على علامة تشير إلى إزالة الوحدة.
يضمن المترجم ثبات معرفات الوحدات ومعرفات chunks بين هذه البنيات. عادةً يخزن هذه المعرفات في الذاكرة، مثلًا مع webpack-dev-server، لكن يمكن أيضًا تخزينها في ملف JSON.
داخل الوحدة
HMR ميزة اختيارية لا تؤثر إلا في الوحدات التي تحتوي كود HMR. مثال على ذلك تحديث التنسيقات عبر style-loader. لكي يعمل التحديث، ينفذ style-loader واجهة HMR؛ وعندما يتلقى تحديثًا عبر HMR، يستبدل التنسيقات القديمة بالجديدة.
وبالمثل، عند تنفيذ واجهة HMR داخل وحدة، يمكنك وصف ما يجب أن يحدث عند تحديث هذه الوحدة. لكن في معظم الحالات، لا يكون من الضروري كتابة كود HMR في كل وحدة. إذا لم تكن لدى الوحدة معالجات HMR، يصعد التحديث إلى الأعلى. هذا يعني أن معالجًا واحدًا يمكنه تحديث شجرة وحدات كاملة. وإذا حُدثت وحدة واحدة من الشجرة، يعاد تحميل مجموعة التبعيات بالكامل.
راجع صفحة HMR API للتفاصيل حول واجهة module.hot.
داخل وقت التشغيل
هنا تصبح الأمور أكثر تقنية قليلًا. إذا لم تكن مهتمًا بالتفاصيل الداخلية، يمكنك الانتقال مباشرة إلى صفحة HMR API أو دليل HMR.
بالنسبة إلى runtime الخاص بنظام الوحدات، يُصدر كود إضافي لتتبع parents و children لكل وحدة. ومن جهة الإدارة، يدعم runtime طريقتين: check و apply.
ينفذ check طلب HTTP إلى update manifest. إذا فشل الطلب، فهذا يعني عدم توفر تحديث. وإذا نجح، تُقارن قائمة chunks المحدثة بقائمة chunks المحملة حاليًا. لكل chunk محمل، يُحمّل update chunk المقابل. تُخزن كل تحديثات الوحدات في runtime. عندما تُحمّل كل update chunks وتصبح جاهزة للتطبيق، ينتقل runtime إلى حالة ready.
تضع طريقة apply علامة invalid على كل الوحدات المحدثة. ولكل وحدة invalid يجب أن يكون هناك معالج تحديث في الوحدة أو في أحد آبائها. وإلا فإن علامة invalid تصعد إلى الأعلى وتبطل الآباء أيضًا. يستمر هذا الصعود حتى يصل إلى نقطة دخول التطبيق أو إلى وحدة لديها معالج تحديث، أيهما يأتي أولًا. إذا صعد من نقطة دخول، تفشل العملية.
بعد ذلك، تُزال كل الوحدات invalid عبر dispose handler وتُفرغ من الذاكرة. ثم يُحدّث الهاش الحالي وتُستدعى كل معالجات accept. يعود runtime إلى حالة idle ويستمر كل شيء كالمعتاد.
ابدأ
يمكن استخدام HMR أثناء التطوير كبديل لـ LiveReload. يدعم webpack-dev-server وضع hot الذي يحاول التحديث عبر HMR قبل محاولة إعادة تحميل الصفحة بالكامل. راجع دليل Hot Module Replacement للتفاصيل.



