هيكل المجلدات القائم على الميزات
نظّم الشيفرة حسب مجال الميزة بدلًا من نوعها، وضع الاختبارات والأنماط والمكوّنات معًا، وفرض الحدود باستخدام eslint-plugin-boundaries
هيكل المجلدات القائم على الميزات درس مجاني في Frontend Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Frontend Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Frontend Academy 4 دروس في المجموع.
طريقتان لتنظيم الشيفرة
يمكنك تجميع الشيفرة حسب النوع (components/ وhooks/ وservices/ وtypes/) أو حسب الميزة (auth/ وcheckout/ وdashboard/، بحيث يحتوي كل منها على components وhooks وغيرها). ويكون التنظيم حسب الميزة أفضل في التطبيقات المتوسطة والكبيرة.
التنظيم حسب النوع — الفخ الافتراضي
يجمع هيكل دروس React التقليدي كل شيء حسب النوع. لكنه لا يتوسع جيداً: إذ يطال كل تغيير في ملف مجلدات متعددة غير مترابطة، كما أن عبارة «العثور على كل شيفرة checkout» تعني البحث باستخدام grep في الشجرة بأكملها.
// Type-based (avoid for large apps):
src/
components/
Button.tsx
LoginForm.tsx
CartItem.tsx
hooks/
useAuth.ts
useCart.ts
services/
auth.ts
cart.ts
types/
User.ts
CartItem.tsالهيكل القائم على الميزات
اجمع كل ما يرتبط بميزة في مجلد واحد. سيكون العثور عليه وحذفه وفهمه سهلاً.
src/
features/
auth/
LoginForm.tsx
SignupForm.tsx
useAuth.ts
auth.service.ts
auth.types.ts
auth.test.tsx
cart/
CartItem.tsx
CartSummary.tsx
useCart.ts
cart.service.ts
cart.types.ts
shared/
components/
Button.tsx
hooks/
useDebounce.tsوضع العناصر ذات الصلة معاً داخل الميزة
يحتوي مجلد الميزة على components وhooks وservices وtypes وtests، أي كل الشيفرة اللازمة لذلك المجال. إذا أراد مطوّر جديد فهم auth، فعليه فتح auth/. وإذا أردت حذف auth، فاحذف المجلد.
المشترك مقابل الخاص بالميزة
تُنقل الشيفرة المستخدمة في ميزتين أو أكثر إلى shared/ (أو lib/). أما الشيفرة المستخدمة في ميزة واحدة فتبقى داخلها. قاوم فكرة «قد نعيد استخدامها لاحقاً» — وانتظر الاستخدام الثاني قبل استخراجها.
قواعد حدود الميزات
ينبغي ألا تستورد الميزات من بعضها مباشرة. إذا احتاجت ميزتان إلى مشاركة شيفرة، فانقل الجزء المشترك إلى shared/. وإذا احتاجتا إلى التنسيق، فاستخدم الأحداث أو مخزناً مشتركاً على مستوى التطبيق.
فرض الحدود باستخدام ESLint
استخدم eslint-plugin-boundaries أو eslint-plugin-import لفرض القاعدة التالية: يمكن للميزات الاستيراد من shared، لكن لا يمكنها الاستيراد من بعضها.
// .eslintrc.json
{
"plugins": ["boundaries"],
"settings": {
"boundaries/elements": [
{ "type": "feature", "pattern": "src/features/*" },
{ "type": "shared", "pattern": "src/shared/*" }
]
},
"rules": {
"boundaries/element-types": ["error", {
"default": "disallow",
"rules": [
{ "from": "feature", "allow": ["shared"] },
{ "from": "shared", "allow": ["shared"] }
]
}]
}
}واجهة عامة لكل ميزة
تصدّر كل ميزة واجهة عامة عبر features/auth/index.ts. وتستورد الشيفرة الأخرى من '@/features/auth' بدلاً من المسارات العميقة. يتيح لك ذلك إعادة هيكلة التفاصيل الداخلية دون كسر الشيفرة المستهلكة لها.
// features/auth/index.ts
export { LoginForm } from './LoginForm';
export { useAuth } from './useAuth';
export type { User, AuthState } from './auth.types';
// Consumers:
import { LoginForm, useAuth } from '@/features/auth';
// NOT: import { LoginForm } from '@/features/auth/LoginForm';تضمين الميزات الفرعية
يمكن للميزات الكبيرة أن تحتوي على مجلدات فرعية: dashboard/widgets/ وdashboard/charts/. تجنّب التضمين لأكثر من مستويين أو ثلاثة — إذ يصبح البحث مرهقاً.
أين توضع المسارات
يمكن وضع الصفحات والمسارات في مجلد pages/ أو routes/ على المستوى الأعلى. وتكون هذه الملفات بسيطة؛ إذ تستدعي components وhooks من الميزات وتنسّق بينها.
src/
pages/
Dashboard.page.tsx // composes Dashboard widgets from features/dashboard/
Cart.page.tsx // composes from features/cart/
features/
shared/ترحيل تطبيق موجود
ابدأ بالميزات الجديدة فقط، وضع الشيفرة الجديدة في features/. لا تعِد هيكلة كل شيء دفعة واحدة. وعندما تلمس الملفات القديمة، انقلها تدريجياً. تمنع قواعد حدود ESLint التراجع عن الهيكل الجديد.
متى يظل التنظيم حسب النوع مناسباً
يُعد التنظيم حسب النوع مناسباً للتطبيقات الصغيرة جداً (أقل من 30 مكوّناً) أو للمكتبات. استخدم التنظيم حسب الميزة بمجرد أن يصبح لديك مجالات أعمال متميزة مثل auth وcheckout وbilling وsettings.
اختبار سريع
ما الفائدة التنظيمية الأساسية لتجميع الشيفرة حسب الميزة بدلاً من نوع الملف؟
مراجعة: الهيكل القائم على الميزات
يحتوي features/ على الشيفرة الخاصة بالمجالات، بينما يحتوي shared/ على الأدوات المشتركة بين الميزات. تصدّر كل ميزة ملف index.ts عاماً. ولا تستورد الميزات من بعضها، بل من shared فقط. افرض ذلك باستخدام eslint-plugin-boundaries. وتنسّق الصفحات والمسارات بين الميزات. أجرِ الترحيل تدريجياً. ويظل التنظيم حسب النوع مناسباً للتطبيقات الصغيرة.
الأسئلة الشائعة
هل درس «هيكل المجلدات القائم على الميزات» مجاني؟
نعم — نص درس «هيكل المجلدات القائم على الميزات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Frontend Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Frontend Academy 4 دروس في المجموع.
ماذا ستتعلم في «هيكل المجلدات القائم على الميزات»؟
نظّم الشيفرة حسب مجال الميزة بدلًا من نوعها، وضع الاختبارات والأنماط والمكوّنات معًا، وفرض الحدود باستخدام eslint-plugin-boundaries تتمرن على Frontend Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Frontend Academy؟
لا تُشترط خبرة سابقة. Frontend Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «هيكل المجلدات القائم على الميزات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Frontend Academy هذا؟
نعم. كل درس في Frontend Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- التصميم الذري: الذرات والجزيئات والكائنات
- إعداد Monorepo باستخدام Turborepo
- الواجهات الأمامية المصغّرة: Module Federation
- هيكل المجلدات القائم على الميزات