تحسين محركات البحث في Angular

كيفية جعل تطبيقات Angular قابلة للزحف والفهرسة — مقارنة @angular/ssr بالتصيير المسبق والتصيير الهجين، وhydration، وخدمتي Title وMeta، وتوجيه History API، واختبار ما يصيّره Googlebot فعلًا.

نُشر أول مرة: 26 يونيو 2026 · آخر تحديث: 22 أغسطس 2026 · Advanced
اللغات

تحسين محركات البحث في Angular هو قرار واحد أساسًا: أرسل HTML حقيقيًا بدل shell مصيَّر من جهة العميل. يدمج Angular الحديث (v17+) SSR في CLI عبر @angular/ssr — صَيِّر المسارات الثابتة مسبقًا، والمسارات الديناميكية من الخادم، واستخدم hydration كي لا يُهدر HTML. ثم طبّق الأساسيات: عناوين وأوصاف فريدة عبر خدمتي Title وMeta في Angular، وتوجيه HTML5 History (من دون عناوين hash)، وروابط <a href> حقيقية، وتحقق باستخدام URL Inspection. التصيير الديناميكي حل التفافي لا استراتيجية — وAngularJS إطار مختلف.

الخلاصة — Angular SEO قرار معماري واحد يرتدي قبعات كثيرة: أدخل HTML حقيقيًا في الاستجابة بدل غلاف مصير على العميل. يدمج Angular الحديث (v17+) SSR في CLI بوصفه @angular/ssr (الخليفة المعاد تسميته والمدمج لـAngular Universal). صير المسارات الثابتة مسبقًا، وصير الديناميكية على الخادم، وامزج بينها بالتصيير الهجين، ثم رطّب الصفحة كي يُعاد استخدام HTML الخادم لا بناؤه من جديد. وبعد ذلك عالج الأساسيات: عناوين/أوصاف فريدة عبر خدمتي Title/Meta (أو TitleStrategy في الموجّه)، وتوجيه HTML5 History — لا تستخدم HashLocationStrategy مطلقًا — وروابط حقيقية من نوع <a href>، وJSON-LD يحقن بأمان، والتحقق عبر URL Inspection. والتصيير الديناميكي حل التفافي تقر به Google، لا استراتيجية.

Evidence for this claim Modern Angular documents @angular/ssr as its server-side and hybrid rendering package. Scope: Current Angular documentation; historical Angular Universal details are not required for this claim. Confidence: high · Verified: Angular: Server-side and hybrid rendering

المشكلة في الإعداد الافتراضي: التصيير من جانب العميل

يأتي بناء Angular الجاهز بملف index.html يحتوي جسمه عمليًا على <app-root></app-root> مع وسوم script. ومن دون تنفيذ JavaScript لا يرى برنامج الزحف عناوين أو نصًا أو روابط — إذ يتجمع المحتوى في المتصفح بعد تحميل الحزمة. وهذه هي المشكلة الأساسية نفسها التي أصفها في JavaScript SEO: انتقل الويب بعيدًا عن HTML البسيط، وCSR هو الطرف الأكثر مخاطرة من ذلك الطيف.

(تعكس تفاصيل التطبيق في هذا الدليل — واجهات RenderMode ومرشحات hydrate وإعادة الأحداث — Angular v22. والميزات الخاصة بالإصدارات أدناه مؤرخة: إعادة تسمية SSR في v17، وإعادة الأحداث في v18، والترطيب التدريجي في v19–v20.)

ينشئ CSR ثلاث مشكلات SEO متميزة:

  1. فهرسة متأخرة وأقل موثوقية. تعالج Google تطبيقات JS في ثلاث مراحل — “Crawling, Rendering, and Indexing” (ترجمة) «الزحف والتصيير والفهرسة» — ويؤجل التصيير إلى قائمة انتظار. ولا يصبح محتواك موجودًا للفهرسة حتى تنفذ تلك المرحلة.
  2. Core Web Vitals أسوأ. يتضرر LCP لأن المتصفح يجب أن ينزل حزمة قبل رسم محتوى ذي معنى وينفذها.
  3. ترى برامج الزحف غير التابعة لـGoogle الغلاف. فـBingbot أقل اتساقًا بكثير في تصيير JS، وبرامج زحف معاينات الشبكات الاجتماعية/الروابط لا تصير عادةً على الإطلاق — لذلك لا تصل وسوم Open Graph والمحتوى المحقون من جانب العميل إليها.

كيف يتعامل Googlebot فعلًا مع تطبيق Angular؟

Googlebot دائم التجدد — فهو يصير باستخدام إصدار حالي من محرك V8 في Chrome ويتحدث مع إصدارات Chrome. Evidence for this claim Googlebot uses an evergreen version of Chromium for rendering. Scope: Google Search rendering engine; this does not remove application-level rendering risks. Confidence: high · Verified: Google: Evergreen Googlebot لذلك يستطيع تشغيل Angular. لكن لسلوكه حدودًا صلبة يجدر أن تصمم حولها:

  • التصيير موضوع في قائمة انتظار، لا فوري. توثق Google مراحل الزحف والتصيير والفهرسة المنفصلة، ولا تنشر جدولًا ثابتًا للمدة التي يحتاجها التصيير ليلحق بالزحف. والاختصار المتداول لهذا هو «موجتان» — يفهرس HTML الخام أولًا (غلاف فارغ في CSR Angular)، ثم يفهرس DOM المصيّر لاحقًا عندما تنفذ تلك المرحلة. يتجاوز SSR/التصيير المسبق الانتظار: يكون HTML كاملًا عند الجلب الأول، فلا توجد مرحلة تصيير منفصلة تنتظرها تلك المادة.
  • المصيّر عديم الحالة. لا ملفات تعريف ارتباط ولا localStorage ولا sessionStorage تنتقل بين عمليات التحميل؛ ويرفض مطالبات الأذونات. لا تجعل المحتوى مشروطًا بحالة العميل.
  • لا ينقر ولا يمرر الصفحة، ويصير عند نافذة عرض عالية جدًا. ولن يرى المحتوى الموجود خلف تفاعل.
  • تُخزن الموارد مؤقتًا بشدة — استخدم أسماء ملفات تحمل بصمة المحتوى (مثل main.<hash>.js الافتراضي في Angular) حتى لا تُقدم حزم محدثة قديمة.

@angular/ssr — ماهيته وتاريخ التسمية

يشغّل التصيير من جانب الخادم Angular على خادم Node عند كل طلب ويعيد HTML مصيرًا بالكامل، ثم يرطّبه المتصفح (يربط معالجات الأحداث بـDOM الموجود بدل إعادة التصيير). ويحصل كل برنامج زحف — Googlebot وBingbot والروبوتات الاجتماعية — على HTML كامل من الطلب الأول، من دون الحاجة إلى موجة ثانية.

تسبب التسمية ارتباكًا، لذلك كن دقيقًا: كان Angular Universal حل SSR التاريخي، يُشحن كحزمة خارجية (@nguniversal/express-engine). ومع Angular v17 (نوفمبر 2023) دُمج SSR مباشرةً في Angular CLI وApplication Builder وأعيدت تسميته @angular/ssr؛ ومستودع Angular Universal الآن في وضع الصيانة. Evidence for this claim Modern Angular documents @angular/ssr as its server-side and hybrid rendering package. Scope: Current Angular documentation; historical Angular Universal details are not required for this claim. Confidence: high · Verified: Angular: Server-side and hybrid rendering والإعداد الآن أمر واحد:

# New project with SSR enabled
ng new my-app --ssr

# Add SSR to an existing project
ng add @angular/ssr

هذا يستبدل ng add @nguniversal/express-engine القديم. الفكرة نفسها، لكن الأدوات أصبحت من الدرجة الأولى.

التصيير المسبق (التوليد الثابت / SSG)

ينشئ التصيير المسبق HTML ثابتًا للمسارات وقت البناء، فلا يعمل خادم وقت الطلب — ويمكنك النشر على CDN. ويمنح أسرع TTFB/FCP/LCP وأقل كلفة تشغيلية. وفي v17+ تضبطه لكل مسار عبر ملف مسارات خادم (app.routes.server.ts) باستخدام RenderMode.Prerender، وينتج outputMode: 'static' تطبيقًا ثابتًا بالكامل.

القيد هو أن البيانات يجب أن تكون متاحة وقت البناء، ولا يوجد محتوى لكل مستخدم، كما تعني المواقع الكبيرة جدًا عمليات بناء بطيئة. وهو مثالي لصفحات التسويق والوثائق ومقالات المدونة — أي المحتوى الذي يحتاج أكثر من غيره إلى الترتيب والاستشهاد.

التصيير الهجين — اختر نمطًا لكل مسار

أكبر تقدم منذ v17+ هو أن نمط التصيير قرار لكل مسار، تضبطه في app.routes.server.ts:

  • RenderMode.Prerender — مسارات ثابتة (الرئيسية، وعن، ومقالات المدونة).
  • RenderMode.Server — مسارات ديناميكية لكل طلب (نتائج البحث ولوحات البيانات ذات البيانات الجديدة).
  • RenderMode.Client — مسارات داخلية فقط لا تريد فهرستها أصلًا (واجهات الإدارة والشاشات التي تتطلب تسجيل الدخول). ويكون CSR مناسبًا فعلًا هنا.

هذه قاعدة القرار عمليًا: صير مسبقًا ما هو ثابت، وصير على الخادم ما يجب أن يكون جديدًا، ولا تعد إلى التصيير من جانب العميل إلا فيما ينبغي ألا يدخل الفهرس.

الترطيب — والمطب الذي يحطم CLS

في SSR الساذج عيب: يرسل الخادم HTML، ثم يرميه المتصفح ويعيد التصيير من الصفر، مما يسبب وميضًا وعملًا مهدورًا. ويصلح الترطيب ذلك — إذ يستعيد المتصفح التطبيق المصير من الخادم ويعيد استخدام DOM المطابق بدل هدمه وإعادة إنشائه، ولا يضيف إلا التفاعلية. فعّله في app.config.ts:

provideClientHydration()

المتطلب السابق: الترطيب رفيق من جانب العميل لـSSR، وليس مفتاحًا مستقلًا. لا تفعل provideClientHydration() شيئًا إلا على مسار مصير على الخادم (أو مصير مسبقًا) بالفعل — ولا تستطيع تحويل غلاف مسار RenderMode.Client إلى HTML خادم. فعّل SSR/التصيير المسبق للمسار أولًا.

توجد قدرتان أحدث مهمتان لتجربة المستخدم المجاورة لـSEO — ولا تغير أي منهما فهرسة البحث:

  • إعادة الأحداث (v18+): تلتقط تفاعلات المستخدم المدعومة التي تحدث قبل انتهاء الترطيب، ثم تعيدها بعد اكتماله. وتقلل النقرات المفقودة لأنواع التفاعل التي تدعمها؛ وهي ميزة UX/تفاعلية لا SEO، ولا تؤثر في ما تفهرسه Google.
  • الترطيب التدريجي (معاينة مطور في v19، مستقر في v20): يعتمد معًا على SSR والترطيب والعروض القابلة للتأجيل وإعادة الأحداث — وليس ميزة مستقلة. وتدعمه كتل @defer ذات محفزات ترطيب تتحكم في الحدود التي تبقى غير مرطبة عند التصيير الأولي؛ وتبقى حدود hydrate never غير مرطبة عند التحميل الأول، لكنها لا تُمنع بالضرورة من تحميل تبعياتها في تصييرات العميل اللاحقة (مثل تغيير المسار). وأثره المتعلق بـSEO غير مباشر: قد يساعد ترطيب JavaScript أقل في البداية LCP، لكن إعداد المحفز تفصيل تصيير لا آلية توقيت للزحف.

المطب الحرج: يؤدي وضع @if (isPlatformBrowser(...)) مباشرةً في القالب إلى جعل الخادم والعميل يصيران ترميزًا مختلفًا — أي عدم تطابق في الترطيب — مما ينتج تحركًا في التخطيط ويضر CLS. استخدم afterNextRender() للعمل الخاص بالمتصفح بدل تفرع القالب حسب المنصة.

العناوين ووسوم meta — خدمات Angular المدمجة

لا يستطيع Angular ربط النص داخل عنصر <title> مباشرةً، لذلك تدير وسوم الرأس عبر خدمتين من @angular/platform-browser:

  • TitlesetTitle() / getTitle().
  • MetaaddTag() وaddTags() وupdateTag() وgetTag() وremoveTag()، مع محددات مثل name='description' أو property='og:title'.

لا تحتاج إلى مكتبة خارجية للأساسيات. وخدمة SEO مشتركة هي النمط الأنظف:

@Injectable({ providedIn: 'root' })
export class SeoService {
  private title = inject(Title);
  private meta = inject(Meta);

  updatePage(title: string, description: string) {
    this.title.setTitle(title);
    this.meta.updateTag({ name: 'description', content: description });
    this.meta.updateTag({ property: 'og:title', content: title });
  }
}

للعناوين تحديدًا، يتيح TitleStrategy في الموجّه (Angular v14+) ضبط title مباشرةً في إعداد المسار، فيُحدّث عنوان الصفحة تلقائيًا عند التنقل — من دون كود لكل مكوّن. ولا تضبط document.title = ... يدويًا؛ استخدم خدمة Title كي تعمل بصورة صحيحة تحت SSR.

بنية عناوين URL

  • استخدم توجيه HTML5 History API الافتراضي (PathLocationStrategy) — عناوين نظيفة مثل /products/shoes. ويحتاج إلى <base href="/"> في index.html.
  • لا تستخدم HashLocationStrategy / useHash: true للمحتوى العام. تُزال معرفات الأجزاء بعد # قبل طلب HTTP، فلا يراها الخادم ولا يستطيع Googlebot حل #/products بصورة موثوقة — وقد ينهار موقعك كله إلى عنوان URL واحد.
  • استخدم روابط <a href> حقيقية للتنقل، بما فيها المسارات المحملة كسولًا. التحميل الكسول جيد للأداء، لكن الروابط إلى تلك المسارات يجب أن تبقى مراسي قابلة للزحف، لا معالجات نقر.

البيانات المنظمة (JSON-LD)

تدعم Google حقن JSON-LD باستخدام JavaScript. والنمط المتين في Angular هو خدمة تنشئ <script type="application/ld+json"> وتضيفه إلى document.head، باستخدام رمز حقن Angular DOCUMENT بدل لمس document عالميًا (مما يكسر العمل على الخادم). أبقِ كل schema في مكان واحد — لا تقسّمه بين HTML الثابت وDOM المصير — وتحقق باستخدام اختبار النتائج الغنية وURL Inspection.

التصيير الديناميكي — حل التفافي قديم، لا خطة

يقدم التصيير الديناميكي نسخة مصيرة مسبقًا للروبوتات (عبر Puppeteer أو Rendertron أو prerender.io) وتطبيق SPA كاملًا للمستخدمين. وتوضح Google أن “dynamic rendering is a workaround and not a long-term solution,” (ترجمة) «التصيير الديناميكي حل التفافي وليس حلًا طويل الأمد»، وأن هناك “better solutions than dynamic rendering” (ترجمة) «حلولًا أفضل من التصيير الديناميكي» — وهي التصيير من جانب الخادم أو التصيير الثابت أو الترطيب. وهو ليس إخفاءً تلقائيًا ما دمت تقدم محتوى متشابهًا جوهريًا، لكنه يضيف خادم تصيير آخر، ويخاطر بانجراف المحتوى، ولا يفعل شيئًا لـCore Web Vitals لدى المستخدمين الحقيقيين. وفي بناء Angular جديد، استخدم @angular/ssr أو التصيير المسبق بدلًا منه.

أخطاء SEO الشائعة في Angular

  1. توجيه hash (عناوين #) — يبدو الموقع كله عنوان URL واحدًا.
  2. لا استدعاءات لـTitle/Meta — تشترك كل صفحة في عنوان ووصف واحد.
  3. لا SSR/تصيير مسبق — لا يوجد المحتوى إلا بعد موجة التصيير المؤجلة.
  4. حظر .js/.css في robots.txt — لا تستطيع Google التصيير وتفهرس غلافًا فارغًا.
  5. إعادة 200 في عرض غير موجود — خطأ 404 ناعم؛ أعد 404 حقيقيًا أو أضف noindex.
  6. استخدام document.title = ... بدل خدمة Title.
  7. وضع isPlatformBrowser() داخل @if في القالب — عدم تطابق الترطيب → CLS.
  8. لمس window/localStorage/document في كود يعمل على الخادم — تعطل SSR.
  9. تقسيم schema بين HTML الخام وDOM المصير.
  10. الاختبار في التطوير المحلي بدل URL Inspection — اعتماد على الافتراضات لا Googlebot.

اختبار Angular من أجل SEO

  • URL Inspection (Search Console) هو مصدر الحقيقة: يعرض منظور الصفحة التي زُحفت، أي HTML المصير — DOM بعد أن شغّل Googlebot JavaScript — وهو ما يُفهرس، إلى جانب رسائل وحدة JS والموارد المحجوبة. شغّل Live Test لتصيير عند الطلب.
  • استخدم curl لجلب عنوان URL لترى HTML الخام قبل JS — فالغلاف الفارغ يعني CSR بلا SSR.
  • اختبار النتائج الغنية يتحقق من البيانات المنظمة.
  • Ahrefs Site Audit (مع تشغيل تصيير JS) وScreaming Frog (وضع JS) يقارنان DOM الخام بالمصير على نطاق واسع.
  • Lighthouse / PageSpeed Insights لقياس أثر خيار التصيير في Core Web Vitals.

Angular ليس سيئًا لـSEO — بل مختلف. أدخل HTML حقيقيًا في الاستجابة، وأدر وسوم الرأس، وأبقِ عناوين URL والروابط قابلة للزحف، ودع أدوات Google نفسها تفصل في المخرج المصير. يقع هذا الموضوع إلى جانب JavaScript SEO وأسئلة تصيير CMS عديم الرأس في هذا العنقود — والدرس الأساسي واحد بينها جميعًا: نمط التصيير يقرر كل شيء تقريبًا.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.