دروس من الإنتاج في Next.js App Router
هاجرنا خلال العام الماضي 11 مشروعًا من Pages Router إلى App Router. هذه القائمة ليست إعلانًا — بل مجموعة قرارات عمليّة نأخذها اليوم تلقائيًا، وأخطاء ندفع ثمنها.1. قرّر مبكرًا: static / dynamic / ISRكل Route يحتاج قرارًا …

هاجرنا خلال العام الماضي 11 مشروعًا من Pages Router إلى App Router. هذه القائمة ليست إعلانًا — بل مجموعة قرارات عمليّة نأخذها اليوم تلقائيًا، وأخطاء ندفع ثمنها.
1. قرّر مبكرًا: static / dynamic / ISR
كل Route يحتاج قرارًا واعيًا. لا تترك revalidate بدون قيمة. نستخدم عادة:
- صفحات تسويقية ثابتة:
export const revalidate = false. - صفحات محتوى دوري (مدوّنة/مشاريع):
revalidate = 300مع tags. - صفحات تخصيص المستخدم:
dynamic = "force-dynamic"+ server components.
2. لا تخلط بين Server / Client Components
القاعدة عندنا: كل page.tsx server. أي شيء يحتاج حالة محلية، framer-motion، أو event handlers نضعه في مكوّن منفصل بـ "use client".نتج عن ذلك هبوط 28% في حجم bundle على صفحة الهبوط.
3. Cache tags أهم ممّا تعتقد
استخدم next: { tags: ["projects"] } على الـ fetch، ثم أطلق webhook من الـ BE (Laravel) إلى /api/revalidate مع قائمة الـ tags. النتيجة: Cache محليّة لحدّ ما تُلمس، وتُفرغ تمامًا لحظة تحديث المحتوى.
4. Streaming + Suspense
قدّم Skeleton فوريًا للهيكل، ثم stream الأجزاء البطيئة. للعميل هذا يعني LCP أسرع ومعدّل ارتداد أقلّ.
5. أخطاء شائعة اكتشفناها
- نسيان
Accept-Languageفي الـ fetch فيرجع لهجة غير متطابقة مع الصفحة. - الاعتماد على searchParams مع صفحة static: ستحصل على خطأ build.
- إعادة توجيه في Middleware بدون تمرير pathname: RTL/Dir يُضبط غلط.
خلاصة عملية
App Router ليس «مجرد ترقية» — بل تغيير في العقلية. إذا جاوبت على السؤالين: «أين تسكن حالة الطلب؟» و«كيف تُفرغ الـ Cache؟» في بداية كل feature — ستكسب سرعة وصلابة لا يقدّمها Pages Router.


