مستودع واحد (Monorepo) مع JavaScript: تنظيم الكود وأفضل الممارسات
غالبًا ما يواجه التطوير الحديث باستخدام JavaScript (Node.js) مشكلة إدارة الكود في المشاريع الكبيرة. عندما يزداد عدد الخدمات المصغرة والمكتبات والتطبيقات، تبدأ المستودعات متعددة الوحدات التقليدية (Polyrepo) في إحداث فوضى: تكرار التكوينات، وصعوبات في مزامنة الإصدارات، وCI/CD طويل. الحل هو المستودع الواحد (monorepo). في هذه المقالة، سنشرح كيفية تنظيم الكود في مستودع واحد باستخدام JavaScript، وما هي الأدوات التي يجب استخدامها، وكيفية تجنب الأخطاء الشائعة.
ما هو المستودع الواحد (Monorepo) ولماذا هو مطلوب؟
المستودع الواحد هو نهج يتم فيه تخزين كل كود المشروع (تطبيقات متعددة، مكتبات، خدمات) في مستودع واحد. على عكس Polyrepo، حيث يعيش كل مكون في مستودع Git الخاص به، يقوم monorepo بدمج كل شيء في هيكل واحد.
مزايا المستودع الواحد لـ JavaScript:
- إصدار واحد للتبعيات — تستخدم جميع الحزم نفس إصدارات المكتبات، مما يلغي التعارضات.
- إعادة استخدام الكود — يمكن استيراد الأدوات المساعدة والمكونات المشتركة بسهولة بين المشاريع الفرعية دون نشرها في npm.
- الالتزامات الذرية — يمكن إجراء تغييرات على حزم متعددة في التزام واحد، مما يبسط المراجعة والتراجع.
- CI/CD مبسط — خط أنابيب واحد للمشروع بأكمله، مع تخزين مؤقت للبناءات والاختبارات.
ومع ذلك، فإن للمستودع الواحد عيوبًا أيضًا: فهو يتطلب انضباطًا صارمًا في تنظيم الكود واختيارًا صحيحًا للأدوات. بعد ذلك، سننظر في كيفية تنظيم الهيكل والأدوات التي يجب استخدامها.
أدوات إدارة المستودع الواحد في Node.js
تقدم بيئة JavaScript العديد من الأدوات الناضجة للعمل مع monorepo. دعنا نلقي نظرة على الثلاثة الأكثر شيوعًا:
1. Lerna
أداة كلاسيكية كانت المعيار لفترة طويلة. تدير Lerna نشر الحزم، وإدارة الإصدارات، وتشغيل البرامج النصية عبر جميع الحزم. مثال على تكوين lerna.json:
{ "version": "independent", "packages": ["packages/*"], "npmClient": "yarn"}يقوم الأمر lerna bootstrap بتثبيت التبعيات لجميع الحزم وربطها ببعضها البعض.
2. Nx (Nrwl)
أداة أكثر حداثة وقوة مع نظام تخزين مؤقت متقدم، ورسوم بيانية للتبعيات، ومولدات كود. يدعم Nx ليس فقط JavaScript، بل أيضًا TypeScript وAngular وReact وNext.js. مثال على أمر لإنشاء مكتبة:
npx nx generate @nrwl/node:library my-lib --directory=sharedيقوم Nx تلقائيًا بتحليل التبعيات وإعادة بناء الحزم المتغيرة فقط.
3. Turborepo
تم إنشاؤه بواسطة Vercel، ويركز Turborepo على سرعة البناء والبساطة. يستخدم التخزين المؤقت الذكي والتنفيذ المتوازي للمهام. مثال على turbo.json:
{ "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] }, "test": { "dependsOn": ["build"], "outputs": [] } }}يعتبر Turborepo مثاليًا للمشاريع التي تحتوي على عدد كبير من الحزم حيث تكون سرعة CI مهمة.
تنظيم هيكل المشروع في المستودع الواحد
الهيكل الصحيح للمجلدات هو أساس نجاح monorepo. دعنا نلقي نظرة على هيكل نموذجي لمشروع Node.js:
my-monorepo/├── packages/│ ├── shared-utils/ # أدوات مساعدة مشتركة│ │ ├── src/│ │ │ └── index.js│ │ └── package.json│ ├── api-gateway/ # بوابة API│ │ ├── src/│ │ │ └── server.js│ │ └── package.json│ └── web-app/ # تطبيق ويب (React/Vue)│ ├── src/│ │ └── App.js│ └── package.json├── tools/ # البرامج النصية والتكوينات