كل المقالات والفيديوهات

العرض في تطبيقات المؤسسات: CSR أم SSR أم كلاهما؟

أم لتطبيقات و في المؤسسات: متى يستحق العرض على الخادم كلفته، وثمن الإحياء، و ، والمسارات الكسولة، و ، و .

Adil Ben Moussa
08 نوفمبر 2026· 5 دقائق
العرض في تطبيقات المؤسسات: CSR أم SSR أم كلاهما؟

يضيف فريقٌ العرضَ على الخادم (server-side rendering) إلى لوحة متابعة بنكية داخلية. كل صفحة فيها تتطلب مستخدماً مسجّل الدخول، ولن يراها أي محرك بحث أبداً، وصار على الفريق الآن تشغيل خادم وترقيعه وتدقيقه. التحميل الأول أسرع قليلاً، أما الفاتورة وسطح الهجوم () فأكبر بكثير.

كثير من تطبيقات المؤسسات التي تتطلب تسجيل الدخول لا تحتاج إلى العرض على الخادم. وبعض أجزاء المؤسسة نفسها تحتاج إليه. فالقرار يُتخذ لكل صفحة، لا للشركة كلها.

CSR للتطبيق، و SSR أو التوليد المسبق للصفحات العامة

دليل Angular نفسه صريح بشأن الجانبين. فالعرض على جهة العميل (CSR) «له أبسط نموذج تطوير»، و«لا يحتاج الخادم إلى أي عمل لعرض الصفحة سوى تقديم ملفات JavaScript ثابتة». لكنه «أسوأ أداءً عموماً»، و«قد يؤثر سلباً» في تحسين محركات البحث () للصفحات التي تفهرسها برامج الزحف. أما العرض على الخادم (SSR) فـ«قد يزيد تكاليف استضافة الخادم»، و«يتطلب منك كتابة كود لا يعتمد حصراً على واجهات المتصفح البرمجية».

الصورة: tt-tech.io، مقتبسة من web.dev، Rendering on the web، بترخيص .

لذلك أرسم الخط عند تسجيل الدخول. خلفه (لوحات المتابعة، والمكتب الخلفي، ومعالجة الملفات)، CSR. وأمامه (صفحات المنتجات، والأسعار، والبحث عن الفروع)، ولّد مسبقاً () ما هو متطابق للجميع، واعرض على الخادم ما يتغير مع كل طلب. ويقول web.dev الشيء نفسه بعبارات عامة: «يمكنك دائماً أن تختار العرض على الخادم لبعض الصفحات دون غيرها». ويدعم Angular ذلك لكل مسار عبر RenderMode.Client و Prerender و Server. وغالباً ما يكون الموقع العام والتطبيق ببساطة تطبيقين منفصلين.

الإحياء هو ثمن SSR

يجب أن يتحول القادم من الخادم إلى تطبيق. ويعيد الإحياء () في Angular استخدام الـ الذي عُرض على الخادم. ومن دونه، يهدم Angular ذلك الـ DOM ويعيد عرضه، وهو ما «قد يسبب وميضاً مرئياً في الواجهة». لكنّ «مستمعي الأحداث لا يُربطون إلى أن يكتمل الإحياء»، ولهذا يوفّر Angular إعادة تشغيل الأحداث ().

ويذهب الإحياء التدريجي () أبعد من ذلك: فكتل @defer مع مشغّلات hydrate (عند الخمول، أو عند الظهور على الشاشة، أو عند التفاعل) تتحكم في موعد تحميل Angular لذلك الجزء وإحيائه، وهو ما «قد ينتج حزماً أولية أصغر». وهو «مفعّل افتراضياً حين تستخدم provideClientHydration()». يستحق ذلك في صفحة عامة فيها عنصر واجهة ثقيل، لكنه ليس سبباً لإضافة SSR إلى لوحة متابعة.

@defer لعناصر الواجهة الثقيلة

الرسوم البيانية، ومحررات النصوص المنسّقة، وعارضات ملفات نادراً ما تحتاج إلى أن تكون في الحزمة الأولى. فكتل @defer «تقلّص حجم الحزمة الأولية لتطبيقك بتأجيل تحميل الكود غير الضروري تماماً للعرض الأول للصفحة».

وثمة عقبة تخص المؤسسات: الاعتماديات المؤجَّلة «يجب أن تكون مستقلة (standalone)». فالكود الذي ما زال يعيش في NgModule لا يمكن تأجيله. ركنك القديم هو الذي يقرّر ما تستطيع تحميله تحميلاً كسولاً.

في قاعدة كود قديمة، الركن القديم هو الذي يقرّر ما يمكن تحميله تحميلاً كسولاً.

المسارات الكسولة على حدود الفرق

تقسّم المسارات الكسولة () الحزمة حيث تقسّم فرقك الكود أصلاً: مكتبة ميزة واحدة، ومسار واحد، وجزء واحد من الحزمة. ويشير Angular إلى أن المسارات الكسولة تزيل «أجزاء كبيرة من JavaScript من الحزمة الأولية»، ويوصي بالتحميل المبكر «لصفحة أو صفحات الهبوط الرئيسية»، ويحذّر من أن التحميل الكسول المتداخل بعمق «قد يؤثر في الأداء تأثيراً كبيراً».

وضع zoneless و OnPush افتراضياً

غيّر إعدادان افتراضيان ما يُطلق العرض في Angular. فالعمل دون ‏(zoneless) «هو الافتراضي في Angular v21+». و «هي استراتيجية اكتشاف التغييرات الافتراضية في Angular (منذ v22)». وصار العرض الآن يتبع الإشعارات: تتغير إشارة تُقرأ في قالب، أو يُضبط مُدخل، أو يعمل مستمع في القالب، أو يستدعي الكود markForCheck(). والكود القديم الذي كان يعدّل حقلاً وينتظر أن يلاحظ Zone.js ذلك يحتاج الآن إلى واحد من هذه الإشعارات.

مكوّنات الخادم في React

أما في عالم React، فتُعرض مكوّنات الخادم (Server Components) «مسبقاً، قبل التجميع، في بيئة منفصلة عن تطبيق العميل أو خادم SSR». وهي تناسب الصفحات الغنية بالمحتوى التي تقرأ بياناتها على الخادم. وتأتي عادة مع دوال الخادم ()، التي تنقل خطاً أمنياً إلى مستودع الواجهة الأمامية: فوسائطها «يتحكم فيها العميل بالكامل»، ويطلب منك React أن «تتحقق من أن المستخدم المسجّل مسموح له بتنفيذ ذلك الإجراء». وفي تطبيق خاضع للتنظيم، تلك الدالة نقطة نهاية عامة، وتُراجَع على هذا الأساس.

في Atlas Bank

يُعرض Atlas Bank على جهة العميل عن قصد: خدمات بنكية بعد تسجيل الدخول، ولا حاجة إلى تحسين محركات البحث، ولا خادم Node. وهو يعمل دون Zone.js (يقول ملف AGENTS.md في المستودع: «لا تضف zone.js أبداً»)، وكل ميزة فيه مسار كسول في apps/atlas/src/app/app.routes.ts، بما فيها الشاشات القديمة. وهذان مساران من المسارات الخمسة:

  {
    path: 'accounts',
    loadChildren: () =>
      import('@atlas/feature-accounts').then((m) => m.accountsRoutes),
  },
  {
    path: 'transfers',
    loadChildren: () =>
      import('@atlas/legacy-transfers').then((m) => m.LegacyTransfersModule),
  },

ما زال بإمكان وحدة NgModule القديمة أن تكون مساراً كسولاً، لكنها لا تستطيع أن تكون داخل كتلة @defer. وحتى لوحة المتابعة على '' كسولة، خلافاً لنصيحة Angular بشأن صفحات الهبوط. في تطبيق تجريبي صغير، الفرق صغير؛ أما في تطبيق حقيقي، فسأقيسه.

ما تركته جانباً، ولماذا

  • الجزر (islands)، والاستئناف ()، والعرض على الخادم بالتدفق () بوصفها بنوداً منفصلة. تنويعات خاصة بكل إطار على فكرة «أرسل JavaScript أقل».
  • . تقنية لمواقع المحتوى، تُعرف أكثر من خلال .
  • الـ DOM الافتراضي () مقابل التفاعلية الدقيقة (). نقاش بين الأطر نادراً ما يغيّر قراراً في المنتج.

مع بداية الأسبوع

  • اسرد مساراتك وصنّف كلاً منها: خلف تسجيل الدخول أم لا. المجموعة الثانية وحدها تطرح سؤال SSR.
  • ابحث عن أثقل عنصر واجهة لديك أسفل الشاشة الأولى (). غلّفها بـ @defer (on viewport) وقارن الحزمة الأولية.
  • ابحث عن المكوّنات التي ما زالت تعتمد على Zone.js لملاحظة التغيير. فهي قائمة أعمالك المؤجلة () للانتقال إلى zoneless.

التالي: الجزء الخامس، عن الأداء.

لوكيل البرمجة الخاص بك

قواعد هذا المقال، مكتوبة لوكيل. الصقها في ملف AGENTS.md لديك، أو احفظها مهارةً ()، أو وجّه وكيلك إلى الملف.

لوكيل البرمجة الخاص بك تنزيل ملف ‎.md
# Rendering rules for enterprise apps

Source: https://tt-tech.io/blog/enterprise-frontend-rendering-csr-ssr
For Angular and React frontends. Add to AGENTS.md or save as a skill. Your project's own rules win where they differ.

## Rules

1. Decide rendering per page, not per app. The line is the login: pages behind it use client-side rendering (CSR) by default.
2. Do not add server-side rendering (SSR) to dashboards, back office or other pages behind a login by default. It adds a server to run, patch and audit.
3. For public pages, prerender what is the same for everyone and server-render what changes per request. In Angular, set it per route with `RenderMode.Client`, `RenderMode.Prerender` and `RenderMode.Server`.
4. Code that runs under SSR must not depend on browser APIs. Keep hydration on with `provideClientHydration()`, so Angular reuses the server DOM instead of re-rendering it.
5. Use incremental hydration (`@defer` with `hydrate` triggers such as idle, viewport or interaction) for a heavy widget on a public page. It is not a reason to add SSR.
6. Put heavy widgets below the fold (charts, rich-text editors, PDF viewers) in `@defer`, for example `@defer (on viewport)`.
7. Deferred dependencies must be standalone. Code that still lives in an `NgModule` cannot go in `@defer`; load it through a lazy route instead.
8. Split lazy routes along team lines: one feature library, one route, one chunk. Load primary landing pages eagerly, as Angular recommends, and avoid deeply nested lazy loading.
9. Never rely on Zone.js to notice a change. Trigger rendering through a signal read in the template, an input, a template listener, or `markForCheck()`.
10. Treat every React Server Function (`'use server'`) as a public endpoint. Its arguments are client-controlled: validate them and check that the logged-in user may perform the action.

## Before you say done

- For every new or changed route, state whether it is behind the login and which render mode it uses.
- When you add or move a `@defer` block or a lazy route, run the production build and report the initial bundle size before and after.
- Search changed components for plain fields the template reads and code mutates. Make them signals, or name the notification that renders them.
- Search the diff for `'use server'`. For each function, name where it validates its arguments and checks the user.

المصادر

  1. Angular, Server-side and hybrid-rendering, التوثيق
  2. web.dev, Rendering on the web
  3. Angular, Hydration, التوثيق
  4. Angular, Incremental Hydration, التوثيق
  5. Angular, Deferred loading with @defer, التوثيق
  6. Angular, Lazy-loaded routes, التوثيق
  7. Angular, Angular without ZoneJS (Zoneless), التوثيق
  8. Angular, Skipping component subtrees, التوثيق
  9. React, Server Components, التوثيق
  10. React, 'use server' directive, التوثيق
شارك هذا المقال