Hermes هو محرك JavaScript مع تجميع AOT (Ahead-of-Time)، طورته Meta لـ React Native ومُحسّن للأجهزة المحمولة ذات الذاكرة المحدودة. وفقًا لمدونة Meta Engineering الرسمية (2022)، يقلل Hermes وقت بدء تشغيل التطبيق بنسبة 20-50% ويقلص حجم الحزمة بنسبة 30-40% مقارنة بـ JavaScriptCore. على عكس V8 أو JSC، لا يستخدم Hermes التجميع JIT على الجهاز — يتم تجميع كل JavaScript إلى كود بايت أثناء مرحلة البناء عبر Hermes CLI. هذا مهم بشكل خاص لنظام iOS، حيث أن تجميع JIT مقيد بسياسات App Store.
الملامح الرئيسية
Hermes هو محرك JavaScript مضغوط مفتوح المصدر (ترخيص MIT) أنشأته Meta لـ React Native ومُحسّن للعمل على الأجهزة المحمولة محدودة الموارد. الابتكار الرئيسي لـ Hermes هو التخلي عن التجميع JIT لصالح AOT (Ahead-of-Time). أثناء مرحلة بناء تطبيق React Native، يقوم Metro Bundler بتمرير JavaScript المجمّع إلى Hermes CLI، الذي يحوله إلى كود بايت HBC (Hermes ByteCode). يتم تنفيذ كود البايت هذا مباشرة بواسطة المحرك دون تجميع إضافي على الجهاز. يوفر هذا النهج أداءً قابلًا للتنبؤ: بدون تسخين JIT، بدون توقفات تجميع، بدون استهلاك إضافي للبطارية. تم تصميم Hermes مع مراعاة قيود الأجهزة المحمولة: ذاكرة وصول عشوائي صغيرة (1-4 جيجابايت)، استهلاك محدود للطاقة والحاجة إلى بدء تشغيل بارد سريع. تم الإصدار العام الأول لـ Hermes في عام 2019، واعتبارًا من React Native 0.70 (2022) أصبح المحرك المعيار على Android.
JavaScriptCore (JSC) هو محرك WebKit القياسي المستخدم بواسطة Safari وReact Native قبل الإصدار 0.70. يدعم JSC التجميع JIT، مما يوفر أداءً عاليًا لعمليات JavaScript المعقدة. ومع ذلك، يتطلب JIT تسخينًا: الثواني الأولى من التنفيذ تكون أبطأ (وضع التفسير)، ثم يقوم JIT بتجميع المسارات الساخنة. على iOS، JIT غير متاح عمليًا بسبب سياسات App Store (حظر توليد الكود الديناميكي)، لذلك يعمل JSC على iOS فقط في وضع التفسير — ينخفض الأداء. حجم ملف JSC الثنائي أكبر (حوالي 10 ميجابايت) ويستهلك ذاكرة وصول عشوائي أكثر بسبب البنية التحتية لـ JIT. لا يعتمد Hermes على JIT، مما يوفر أداءً قابلًا للتنبؤ فور بدء التشغيل (بدء بارد). يدعم JSC معيار ECMAScript بشكل أكمل (بما في ذلك Proxy وBigInt وReflect)، ولكن على حساب استهلاك موارد أعلى. لمشاريع React Native حيث يكون البدء البارد والحجم الصغير أمرين حاسمين — Hermes هو الأفضل. للمشاريع ذات العمليات الحسابية الثقيلة على JS (الألعاب، WebGL) — قد يقدم JSC أداءً ذرويًا أعلى.
| المعامل | Hermes | JavaScriptCore |
|---|---|---|
| التجميع | AOT (في مرحلة البناء) | JIT + تفسيري (على الجهاز) |
| البدء البارد | أسرع بنسبة 20-50% | المستوى الأساسي |
| حجم الحزمة | أصغر بنسبة 30-40% | المستوى الأساسي |
| استهلاك RAM | أقل بنسبة 20-30% | المستوى الأساسي |
| ECMAScript | ES2020 (قيود) | ES2022+ (كامل) |
| JIT على iOS | غير مطلوب | غير متاح (تفسيري فقط) |
| الملف الثنائي | ~3 ميجابايت | ~10 ميجابايت |
التجميع AOT (Ahead-of-Time) في Hermes يحدث على مرحلتين. في المرحلة الأولى، يقوم Metro Bundler بجمع ملفات JavaScript في حزمة واحدة ويمررها إلى Hermes CLI (الأداة hermesc). في المرحلة الثانية، يقوم hermesc بتحليل AST لجافا سكريبت، ويُولد تمثيلًا وسيطًا HIR (Hermes Intermediate Representation) ثم يُصدر كود بايت HBC ثنائي. النتيجة — ملف بامتداد .hbc يحتوي فقط على كود بايت بدون JavaScript الأصلي. يقوم وقت تشغيل Hermes بتحميل HBC مباشرة، بدون تحليل وتجميع. هذا يسرع بدء التشغيل بشكل جذري: بدلاً من تحليل آلاف الأسطر من JS (غير متزامن)، يقرأ المحرك تنسيقًا ثنائيًا مُجمَّعًا مسبقًا. AOT أيضًا يقلل الحجم: كود البايت أكثر اكتنازًا من AST لجافا سكريبت بمتوسط 30%. عيب AOT — عدم القدرة على تنفيذ eval أو new Function أو require الديناميكي في وقت التشغيل — يجب أن تكون جميع الوحدات معروفة في مرحلة البناء.
# تثبيت Hermes CLI بشكل مستقل
npm install hermes-engine
# تجميع JS إلى كود بايت HBC
npx hermesc -emit-binary -out bundle.hbc bundle.js
# إحصائيات كود البايت
npx hermesc -dump-bytecode bundle.hbc # shows HBC instructions
# حجم JS الأصلي مقابل HBC
wc -c bundle.js # 2,300,000 bytes
wc -c bundle.hbc # 1,450,000 bytes (37% reduction)
يُقاس أداء Hermes بثلاثة مقاييس رئيسية: Time-To-Interactive (TTI)، حجم APK/IPA واستهلاك RAM. وفقًا لبيانات Meta، على Android يقلل Hermes TTI بنسبة 34% مقارنة بـ JSC: من 4.2 ثانية إلى 2.8 ثانية على جهاز متوسط المدى (Moto G7). ينخفض حجم APK بنسبة 28% بفضل كود البايت المضغوط وغياب مكتبات JIT. استهلاك RAM أقل بمتوسط 22% تحت نفس الحمل — هذا مهم بشكل خاص للأجهزة ذات 2-3 جيجابايت RAM. على iOS، المكسب أكبر: نظرًا لأن JSC لا يمكنه استخدام JIT، يوفر Hermes تحسنًا في TTI يصل إلى 45%. تستند المقاييس إلى اختبارات Meta مع تطبيق Facebook Lite. في المشاريع الحقيقية، يختلف المكسب: للشاشات البسيطة (القوائم، النصوص) يعطي Hermes تحسنًا أكبر، للرسوم المتحركة الثقيلة — أقل. أداة التنميط: React Native Profiler + hermes profile --heap.
Hermes يتضمن ملف تعريف ذاكرة مدمج يمكن الوصول إليه عبر Chrome DevTools. اتصل بالتطبيق عبر Metro، افتح علامة التبويب Memory واختر Hermes (JavaScript) من أنواع اللقطات. يدعم Hermes ثلاثة أنواع من اللقطات: Heap Snapshot (جميع الكائنات)، Allocation Timeline (عمر الكائنات) وAllocation Sampling (ملف تعريف عينة). يقلل Hades GC من توقفات GC إلى الحد الأدنى — في المتوسط توقف واحد لمدة 2-5ms لكل 10 ثوانٍ من التشغيل مقابل توقفات 10-20ms لـ JSC خلال نفس الفترة.
Hades GC هو جامع القمامة في Hermes، مصمم للسيناريوهات المحمولة مع توقفات ضئيلة. على عكس GC mark-sweep في JSC، يستخدم Hades التجميع المتزامن: يعمل الجامع بالتوازي مع سلسلة التنفيذ الرئيسية، ويوقفها فقط لفترات قصيرة. يقسم Hades GC الكومة إلى أجيال: الجيل الصغير (nursery) يُجمع بشكل متكرر وسريع (Scavenge)، الجيل القديم يُجمع بشكل أقل مع توقفات أصغر. حجم الكومة قابل للتكوين: افتراضيًا — 2/3 من RAM المتاحة للتطبيق، الحد الأدنى — 32 ميجابايت. لا يستخدم Hades نهج stop-the-world: حتى التجميع الكامل للجيل القديم لا يستغرق أكثر من 5-8ms. الجامع مُحسّن للسيناريوهات المحمولة النموذجية: العديد من الكائنات قصيرة العمر (سلاسل مؤقتة، كائنات React fiber)، قليل من الكائنات طويلة العمر. للتطبيقات ذات الإنشاء المكثف للكائنات (القوائم، الرسوم المتحركة)، يوفر Hades FPS أكثر سلاسة مقارنة بـ JSC.
تفعيل Hermes يعتمد على إصدار React Native والنظام الأساسي. بدءًا من React Native 0.70، يتم تفعيل Hermes افتراضيًا لـ Android في المشاريع الجديدة. لـ iOS، Hermes اختياري. للتفعيل على Android: في الملف android/app/build.gradle قم بتعيين enableHermes: true في كتلة project.ext.react.enableHermes. لـ iOS: قم بتعيين hermes_enabled إلى true في Podfile عبر use_react_native!(:path => config[:reactNativePath], :hermes_enabled => true). بعد التفعيل، نفذ pod install. للمشاريع الحالية، تحقق من توافق المكتبات: Hermes لا يدعم Proxy وeval وبعض ميزات ES2021. استخدم npx react-native info للتحقق من التكوين. للتبديل بين Hermes وJSC، غيّر العلم وقم ببناء نظيف.
// android/app/build.gradle — تفعيل Hermes
project.ext.react = [
enableHermes: true,
cliPath: "node_modules/react-native/cli.js"
]
// iOS/Podfile — تفعيل Hermes على iOS
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target 'MyApp' do
config = use_native_modules!
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true
)
end
القيود الرئيسية لـ Hermes مرتبطة بعدم وجود JIT. Hermes لا يدعم: Proxy وReflect API (المستخدمة في MobX وVue وبعض مديري الحالة)، BigInt (الأعداد الكبيرة)، Symbol.toStringTag، WeakRef وFinalizationRegistry. الدالتان eval و new Function تُولدان استثناءً أثناء التنفيذ. استدعاءات Array.prototype.flat وflatMap مع وسيطة this تعمل مع قيود. تنسيقات التاريخ ISO 8601 مع المناطق الزمنية لا تتم معالجتها بالكامل. معظم هذه القيود لا تؤثر على تطبيقات React Native النموذجية: React وReact Native يستخدمان مجموعة محدودة من ميزات ES. إذا كانت المكتبة تتطلب Proxy (مثل MobX 6+ مع Proxy)، استخدم configure({ useProxies: false }) أو اختر بديلاً. للتحقق من توافق الكود الموجود، شغّل npx hermesc -check على حزمتك — سيُظهر قائمة الميزات غير المدعومة.
الأسئلة الشائعة
في وحدة تحكم التطبيق، نفذ console.log(global.HermesInternal). إذا كان الكائن HermesInternal موجودًا — التطبيق يعمل على Hermes. بديل: console.log(global.HermesInternal?.getRuntimeProperties()) — سيُخرج إصدار المحرك ومعلمات GC. في إصدارات Release، قد لا يكون HermesInternal متاحًا لتقليل الحجم.
تحقق من إعدادات Podfile: Hermes على iOS يتطلب New Architecture (Fabric Renderer). قم بتعيين :hermes_enabled => true، نفذ pod install --repo-update. إذا كان المشروع يُحدّث من React Native أقل من 0.70، تحقق من توافق المكتبات مع New Architecture. عطّل Hermes إذا كانت مكتبة طرف ثالث تتطلب JSC — غيّر العلم إلى false وأعد تثبيت Pods.
لا، Hermes لا يؤثر على Hot Reload / Fast Refresh. أثناء التطوير، يقوم Metro بتشغيل حزمة JavaScript بدون تجميع Hermes (JS عادي). يتم تجميع كود بايت Hermes فقط لإصدارات Release. في وضع Debug، يُستخدم JavaScriptCore القياسي أو Hermes في وضع التفسير. سرعة Hot Reload لا تتغير عند تفعيل Hermes في التكوين — التبديل يحدث فقط في مرحلة بناء الإنتاج.
نعم، بدءًا من Expo SDK 45، Hermes مدعوم لـ managed workflow. في app.json حدد "jsEngine": "hermes". لـ bare workflow، يعمل Hermes كما في مشروع React Native عادي. Expo Go لا يدعم Hermes — استخدم Expo Dev Client أو EAS Build للإصدارات مع Hermes. تحقق من توافق المكتبات عبر expo doctor.
استخدم React Native Performance Monitor (مقاييس FPS) وHermes Profiling Tools. قم ببناء نسختين من التطبيق — مع Hermes وJSC — على نفس الجهاز. قِس: البدء البارد (من النقر على الأيقونة حتى أول شاشة تفاعلية)، TTI (Time-To-Interactive)، حجم APK/IPA والاستهلاك الأقصى لـ RAM. شغّل الاختبارات 3 مرات على الأقل لكل تكوين. الميزة النموذجية لـ Hermes: بدء أسرع بنسبة 20-40%، RAM أقل بنسبة 15-25%.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.