Metro هو باندلر JavaScript تم تطويره خصيصًا لـ React Native ويستخدم افتراضيًا لبناء تطبيقات الجوال على هذه المنصة. على عكس الباندلرات العامة، تم تحسين Metro ليتناسب مع الموارد المحدودة للأجهزة المحمولة ويوفر التكامل مع محرك Hermes و Fast Refresh. وفقًا لـ Metro Documentation (2026)، يعالج الباندلر أكثر من 90% من مشاريع React Native في العالم.
الملخص
Metro هو باندلر JavaScript مفتوح المصدر أنشأه فريق Meta لـ React Native. حل محل Packager من الإصدارات المبكرة لـ React Native وأصبح أداة البناء القياسية لهذه المنصة. Metro غير مصمم لتطوير الويب: هندسته موجهة حصريًا لتطبيقات الجوال التي تعمل على محركات JavaScript JSC (JavaScriptCore) أو Hermes.
Metro ظهر في عام 2018 كبديل لـ React Native Packager القديم. السبب الرئيسي لإنشائه هو الحاجة إلى باندلر يعمل بكفاءة مع ملايين الوحدات في تطبيقات الجوال الكبيرة. على عكس Webpack، لا يدعم Metro CSS أو HTML أو الصور كوحدات — هذه الموارد تتم معالجتها بواسطة أدوات React Native المنفصلة. Facebook تستخدم Metro لبناء تطبيقها الرئيسي الذي يحتوي على أكثر من 100 ألف ملف.
يتم توزيع Metro عبر npm كحزمة metro ويتم تثبيته تلقائيًا مع React Native CLI. إصدار Metro مرتبط بإصدار React Native، لذلك تحديث الباندلر يحدث مع تحديث المنصة.
Metro يستقبل نقطة دخول التطبيق، ويبني رسمًا بيانيًا للتبعيات، ويحول كل وحدة، ويسلسل النتيجة في حزمة واحدة. تمر العملية بثلاث مراحل: Resolve (حل الوحدات)، Transform (التحويل)، Serialize (التسلسل).
// مثال على إعداد Metro للتحويل المخصص
const metroConfig = {
transformer: {
babelTransformerPath: require('metro-babel-transformer'),
async transform({ src, filename, options }) {
const result = await babelTransform({ src, filename, options });
return {
ast: result.ast,
code: result.code,
map: result.map,
dependencies: [],
};
},
},
serializer: {
createModuleIdFactory() {
let nextId = 0;
const moduleIds = new Map();
return ({ path }) => {
if (!moduleIds.has(path)) {
moduleIds.set(path, nextId++);
}
return moduleIds.get(path);
};
},
},
};
في مرحلة Resolve، يحدد Metro موقع كل وحدة مستوردة، مع مراعاة الأسماء المستعارة و node_modules. في مرحلة Transform، يمر كل ملف عبر محول Babel لتحويل JSX و TypeScript والإضافات الأخرى إلى JavaScript نقي. المرحلة النهائية Serialize تجمع كل الوحدات المحولة في ملف حزمة واحد أو أكثر.
Metro مبني على هندسة معيارية حيث يتم تنفيذ كل مرحلة بناء كمكون منفصل. هذا يسمح باستبدال الوحدات القياسية بوحدات مخصصة دون تغيير نواة الباندلر. تشمل هندسة Metro ثلاث حزم رئيسية: metro و metro-config و metro-resolver.
Metro Server — خادم التطوير الذي يتم تشغيله بأمر npx react-native start. يخدم طلبات تحويل الوحدات في الوقت الفعلي، مما يوفر Fast Refresh. Module Store — ذاكرة تخزين مؤقت تحتفظ بالوحدات المحولة في الذاكرة لتسريع إعادة البناء. Dependency Graph — رسم بياني للتبعيات يتم تحديثه بشكل تدريجي عند تغيير الملفات.
Watchman — مراقب ملفات من Meta يستخدمه Metro لاكتشاف التغييرات في نظام الملفات. بدون Watchman، يضطر Metro إلى إعادة مسح هيكل الملفات بالكامل عند كل تغيير، مما يبطئ التطوير بشكل كبير. تثبيت Watchman إلزامي للعمل المريح مع Metro في المشاريع من أي حجم.
إعداد Metro يُحدد في ملف metro.config.js في جذر المشروع. ملف نموذجي يحدد مجلدات إضافية للبحث عن الوحدات، وقوائم حظر لاستبعاد الملفات غير الضرورية، ومحولات مخصصة. في React Native 0.72+ يتم استخدام الكشف التلقائي عن الإعداد، ولكن للمستودعات الأحادية (monorepos) الإعداد إلزامي.
// metro.config.js
const config = {
resolver: {
sourceExts: ['js', 'jsx', 'ts', 'tsx', 'json'],
nodeModulesPaths: ['node_modules'],
blockList: [/\.test\.js$/, /__tests__\/.*/],
extraNodeModules: {
'shared-components': path.resolve(__dirname, '../shared/src'),
},
},
transformer: {
minifierConfig: {
keep_classnames: true,
keep_fnames: true,
mangle: { reserved: ['React', 'Component'] },
},
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
blockList يستبعد ملفات الاختبار من البناء، مما يقلل حجم الحزمة. nodeModulesPaths يحدد مسارات إضافية للبحث عن الحزم — أمر بالغ الأهمية للمستودعات الأحادية. extraNodeModules ينشئ أسماء مستعارة للحزم المشتركة المستخدمة في مشاريع مختلفة ضمن المستودع الأحادي.
Metro يوفر عدة آليات لتحسين حجم الحزمة وسرعة البناء. Inline Requires — التقنية الأكثر فعالية، تحول الاستيرادات على المستوى العلوي إلى استدعاءات require محلية داخل الدوال. RAM bundles تسمح بتحميل الوحدات بشكل تدريجي. Hermes يترجم JavaScript إلى كود بايت، مما يقلل حجم التطبيق بنسبة 20–30%.
// metro.config.js — تحسين الإنتاج
const config = {
transformer: {
async transform({ src, filename, options }) {
const inlineRequires = options.dev ? false : true;
return await defaultTransform({ src, filename, options: { ...options, inlineRequires } });
},
},
serializer: {
polyfillModuleNames: [],
},
};
// لتفعيل Hermes — في build.gradle (Android):
// project.ext.react = [enableHermes: true, bundleInRelease: true]
// لـ iOS — في Podfile: :hermes_enabled => true
لتشخيص حجم الحزمة، يوفر Metro العلم --bundle-output مع إخراج إحصائيات. استخدم bundle-visualizer لتحليل مكونات الحزمة والعثور على الوحدات الكبيرة التي يمكن تحميلها بتكاسل. يجب أن يكون التحقق المنتظم من حجم الحزمة جزءًا من خط أنابيب CI/CD لمشروع React Native.
Metro يدعم حزم دلتا — آلية حيث بعد البناء الكامل الأول، يرسل الخادم فقط التغييرات (دلتا) بين الإصدار القديم والجديد من الحزمة. هذا يسرع بشكل جذري عمليات البناء اللاحقة: ينخفض وقت التحديث من ثوانٍ إلى عشرات الميلي ثانية. حزم دلتا فعالة بشكل خاص في مرحلة التطوير، عندما يحفظ المطور التغييرات بشكل متكرر ويعيد تحميل التطبيق.
لتفعيل حزم دلتا في React Native، يُستخدم العلم --delta في أمر npx react-native bundle. على جانب العميل، حزم دلتا مدعومة بدءًا من React Native 0.64. في بنيات الإنتاج، لا تُستخدم حزم دلتا — بدلاً من ذلك، تُستخدم حزمة كاملة مع كود بايت Hermes لأقصى أداء عند التشغيل. يتم تحقيق ذلك لأن الزيادة في سرعة التطوير تعوض تكلفة البناء الكامل الأول.
Hermes هو محرك JavaScript طورته Meta خصيصًا لـ React Native. يقوم Metro بإنشاء كود بايت Hermes في مرحلة البناء، مما يسمح للتطبيق بالتشغيل دون ترجمة JavaScript باهظة الثمن على الجهاز. لتفعيل Hermes، يكفي إضافة enableHermes: true في metro.config.js وإعداد build.gradle أو Podfile. يقلل Hermes وقت تشغيل التطبيق بنسبة 30–50% ويقلص حجم APK بنسبة 20–30% مقارنة بـ JavaScriptCore.
عند استخدام Hermes، من المهم تذكر القيود: المحرك لا يدعم Proxy و Reflect وبعض إمكانيات ES6. معظم تطبيقات React Native لا تستخدم هذه الإمكانيات مباشرة، لكن بعض المكتبات قد تتعارض. قبل تفعيل Hermes، تحقق من توافق جميع تبعيات المشروع عبر قائمة التوافق الرسمية. يتحول Metro تلقائيًا إلى وضع إنشاء كود البايت عند تفعيل Hermes.
لتتبع كفاءة بناء Metro، استخدم المقاييس المدمجة المتاحة عبر Flipper — أداة تصحيح أخطاء React Native. ينشر Metro أحداثًا: bundle_request و transform و resolve مع وقت تنفيذ كل مرحلة. تحليل هذه البيانات يساعد في تحديد الاختناقات: إذا كانت مرحلة التحويل تستغرق أكثر من 70% من الوقت، فالمشكلة في محول Babel. فعّل تسجيل سجلات Metro عبر العلم --verbose للتشخيص التفصيلي.
الأسئلة الشائعة
نعم من الناحية الفنية — توجد مشاريع تجريبية مثل react-native-webpack، لكنها غير مدعومة رسميًا. Metro متكامل مع جسر React Native و Turbo Modules و Hermes على مستوى غير متاح لـ Webpack. استبدال Metro سيؤدي إلى فقدان Fast Refresh والدعم الرسمي.
React Native لا يستخدم CSS للتنسيق — بدلاً من ذلك يُستخدم تنسيق JavaScript عبر StyleSheet.create. نظرًا لأن Metro تم إنشاؤه حصريًا لـ React Native، فليست هناك حاجة لدعم CSS. لتقديم الويب عبر React Native Web، تتم معالجة CSS بواسطة أدوات منفصلة خارج Metro.
Metro لا يعالج الصور أو الخطوط كوحدات. يتم استيراد الموارد عبر require('./image.png')، لكن Metro يسجلها فقط كتبعيات نصية. التحميل الفعلي للصور يتم بواسطة كود React Native الأصلي عبر مكون Image، ويقوم Metro بنسخ الموارد إلى الحزمة.
Rollup يولد وحدات ES مع tree shaking على مستوى الوحدات، مما يعطي حجم حزمة أدنى للمكتبات. Metro يولد حزمة CommonJS مع تحويل مضمّن وتحسين لمحركات الجوال. Rollup لا يدعم Fast Refresh ولا يمكنه العمل مع الوحدات الأصلية لـ React Native.
البناء البارد لـ Metro يتباطأ بسبب المسح الكامل لـ node_modules. الحلول: أضف watchFolders للمستودعات الأحادية، استخدم maxWorkers للتحويل المتوازي وقم بتثبيت Watchman. للمشاريع التي تحتوي على أكثر من 10,000 ملف، فكر في استخدام metro-memory-fs للتخزين المؤقت في الذاكرة.
الخلاصة
watchFolders و extraNodeModules لحل الوحدات بشكل صحيح.سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.