SEO لتطبيقات الصفحة الواحدة

كيفية جعل تطبيقات الصفحة الواحدة (React Router وVue Router وAngular Router) قابلة للزحف والفهرسة، ومعالجة مشكلات غلاف التطبيق وsoft-404، والمقارنة بين History API والتوجيه بالأجزاء، وتوفير HTML لكل مسار عبر SSR أو العرض المسبق، وضبط العنوان الأساسي وعنوان الصفحة لكل مسار، وإنشاء خريطة الموقع للمسارات من جانب العميل.

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

يحمّل تطبيق الصفحة الواحدة مستندًا واحدًا ويبدّل العروض باستخدام JavaScript بدل طلب صفحة جديدة من الخادم. تنفذ تطبيقات كثيرة ذلك بغلاف تطبيق يعيد HTML حقيقيًا لعنوان URL واحد وغلافًا شبه فارغ لبقية المسارات إلى أن يعرضها JavaScript، لكن هذا تنفيذ شائع لا قاعدة عامة؛ افحص الاستجابة المباشرة لكل مسار. وعندما يكون الغلاف المجرد هو المشكلة، يتكون الإصلاح من جزأين مستقلين: قابلية العنونة عبر History API بدل أجزاء # أو #!، بحيث يكون لكل عرض عنوان URL حقيقي، وتوفر المحتوى عبر SSR أو العرض المسبق أو إطار وسيط، بحيث يعيد كل عنوان HTML فريدًا عند طلبه. تحقق كذلك من عنوان كل مسار وعنوانه الأساسي وحالة robots عند الدخول المباشر وبعد العرض، وعالج soft 404s؛ فالموجّهات تميل إلى إبقاء حالة 200 للعروض غير الموجودة، لذا أعد التوجيه إلى عنوان يعيد 404s بذاته أو أضف noindex بعد العرض، مع الانتباه إلى أن noindex الأولي قد يدفع Google إلى تخطي العرض. وتأكد من أن كل مسار في خريطة الموقع يعيد HTML حقيقيًا قابلًا للفهرسة؛ فلا يوجد تنسيق خاص لخريطة موقع SPA.

الخلاصة — الخطر الأساسي لتحسين محركات البحث في تطبيق SPA ليس “JavaScript” بشكل مجرد — بل هو أن التوجيه من جانب العميل يغير ما يراه المستخدم دون تغيير ما يرسله الخادم. الإصلاح له نصفان مستقلان يخلطهما الناس باستمرار: قابلية العنونة (واجهة برمجة تطبيقات History، عناوين URL فريدة لكل مسار، بدون أجزاء #!) وتوفر المحتوى (SSR، prerendering/SSG، أو إطار عمل وسيط). افعل الأول فقط وستحصل على خريطة موقع مرتبة لعناوين URL تعرض جميعها نفس القشرة. بالإضافة إلى كليهما، يحتاج كل مسار إلى canonical/title/description خاص به في DOM المعروض، وعليك التعامل مع أخطاء soft 404s التي تحتفظ برمز 200، ويجب أن يحل كل مسار في خريطة الموقع بشكل مستقل إلى HTML حقيقي.

ما هو تحسين محركات البحث لتطبيقات SPA فعليًا

SPA بنية تطبيق، وليست حالة فشل حتمية في SEO. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: MDN: Single-page application يمكن للعرض من الخادم أو العرض المسبق أو العرض المنفذ بعناية من جانب العميل أن يكشف المحتوى، لكن لا يضمن أي منها الفهرسة. Evidence for this claim Primary standard or official documentation supporting the adjacent article claim. Scope: Protocol semantics and Search behavior are kept separate; no indexing, ranking, or migration-timing guarantee is inferred. Confidence: high · Verified: Google: JavaScript SEO basics

هذا هو الغوص العميق في التطبيقات ذات الصفحة الواحدة تحديدًا — التوجيه من جانب العميل مع React Router أو Vue Router أو Angular Router، حيث بعد التحميل الأول لا يرسل الخادم صفحة كاملة أخرى أبدًا. يقع هذا بجانب دليل JavaScript SEO الأوسع (الذي يغطي التكافؤ، والتحميل الكسول، والتمرير اللانهائي، وعرض JavaScript عمومًا) والكتابات الخاصة بكل إطار عمل لـ React و Next.js و Nuxt و Angular و Vue و Svelte و Astro. هنا أنا مهتم فقط بطبقة التوجيه وما تفعله بالزحف والفهرسة.

لماذا تفشل تطبيقات SPA ذات التوجيه من جانب العميل في تحسين محركات البحث

عنوان URL واحد، استجابة HTML واحدة — مشكلة غلاف التطبيق

تصف Google وضع الفشل بدقة: “Some JavaScript sites may use the app shell model where the initial HTML does not contain the actual content and Google needs to execute JavaScript before being able to see the actual page content.” (ترجمة) «قد تستخدم بعض مواقع JavaScript نموذج غلاف التطبيق، حيث لا يحتوي HTML الأولي على المحتوى الفعلي، وتحتاج Google إلى تنفيذ JavaScript قبل أن تتمكن من رؤيته». في تطبيق SPA العاري، يكون «غلاف التطبيق» هو كل ما يرسله الخادم. اجلب /products مباشرةً وستحصل على المستند شبه الفارغ نفسه الذي يعيده /about. لا يختلف المحتوى إلا بعد أن يشغّل المتصفح JavaScript ويقرر الموجّه ما يعرضه.

هذه هي المشكلة كلها في جملة واحدة: التوجيه من جانب العميل يغير ما يراه المستخدم دون تغيير ما سيعيده الخادم. كل ما يتبع ذلك — أخطاء soft 404s، والمحتوى المكرر، والعناوين المفقودة — هو عرض من أعراض ذلك.

الخادم لا يرى أبدًا أي “صفحة” تم طلبها (لماذا يفشل توجيه التجزئة)

تطبيقات SPA الأقدم تحمّل العروض من أجزاء URL — example.com/#/products. كلمات Google الدقيقة: “قد يستخدم تطبيق SPA أجزاء URL (على سبيل المثال https://example.com/#/products) لتحميل عروض مختلفة.” يفشل هذا لسبب ميكانيكي محدد: المتصفحات لا ترسل أبدًا الجزء (أي شيء بعد #) إلى الخادم في طلب HTTP. لا يمكن للخادم حرفيًا معرفة أي “صفحة” تم طلبها، لذا لا يمكنه إرجاع محتوى مختلف أو رمز حالة مختلف لها. الزاحف الذي يجلب عنوان URL مرة واحدة يحصل على HTML متطابق بغض النظر عن الجزء.

لهذا السبب أيضًا أوقفت Google رسميًا مخطط الزحف AJAX لعام 2009 في أكتوبر 2015: “باختصار: لم نعد نوصي باقتراح الزحف AJAX الذي قدمناه في عام 2009.” كان الحل القديم _escaped_fragment_ يسمح للخوادم بعرض مسارات التجزئة مسبقًا عند الطلب — لكنه كان يرقع حول مشكلة التوجيه بدلاً من إصلاحها. توصية Google الخاصة التي تحل محله هي History API، المغطاة أدناه.

أخطاء soft 404s — أجهزة التوجيه من جانب العميل تحتفظ بـ 200 لكل شيء

يكاد ذلك يكون حتميًا في تطبيق SPA ذي الغلاف المجرد. تحتفظ الموجّهات من جانب العميل، بحكم تصميمها، بحالة 200 للصفحة الأصلية في كل تنقل افتراضي، بما في ذلك حالات «غير موجود». تشير Google إلى ذلك صراحة: “In a single-page application (SPA), this can be especially difficult. To prevent error pages from being indexed, you can use one or both of the following strategies.” (ترجمة) «قد يكون ذلك صعبًا بصورة خاصة في تطبيق الصفحة الواحدة. ولمنع فهرسة صفحات الخطأ، يمكنك استخدام إحدى الاستراتيجيتين التاليتين أو كلتيهما». وتشرح السبب: “When a SPA is using client-side JavaScript to handle errors they often report a 200 HTTP status code instead of the appropriate status code.” (ترجمة) «عندما يعالج تطبيق SPA الأخطاء عبر JavaScript من جانب العميل، فإنه غالبًا ما يبلغ عن حالة HTTP ‏200 بدل الحالة المناسبة».

النتيجة هي فهرسة العروض الفارغة أو عروض الأخطاء كصفحات 200 رقيقة. توثق Google استراتيجيتين بالضبط هنا، بدقة: إعادة التوجيه (أو إجراء طلب كامل) إلى عنوان URL الذي يعيد خادمه 404/رمز خطأ حقيقي، أو إضافة وسم noindex إلى عرض الخطأ باستخدام JavaScript. انتبه للثانية: إذا كان noindex موجودًا من أول رسم بدلاً من إضافته بعد أن يقرر التطبيق أن المسار غير صالح، فقد يتسبب في تخطي Google لعرض الصفحة تمامًا — لذا تحقق مما يعيده الطلب المباشر قبل تشغيل أي JavaScript، وليس فقط ما يظهر في DOM المعروض بعد ذلك. Evidence for this claim For a client-rendered not-found view, Google documents two approaches: redirect to a URL whose server returns a 404 response, or add noindex with JavaScript; an initial noindex can cause rendering to be skipped, so raw and rendered directives require separate testing. Scope: SPAs Confidence: high · Verified: Fix Search-related JavaScript problems

تكرارات القشرة المشتركة — سبب محتمل، وليس تشخيصًا تلقائيًا

هناك نمط فشل ثانٍ أكثر خفاءً: يتم فهرسة مسارات مختلفة كتكرارات لبعضها البعض لأنها تُعرض لتنتج نفس القالب المشترك للترويسة/التنقل/التذييل. وصف غاري إليس طريقة واحدة يحدث بها هذا: “لدي مجموعة من رسائل البريد الإلكتروني في صندوق الوارد الخاص بي حيث تكون المشكلة أن العنصر الرئيسي استغرق وقتًا طويلاً للتحميل، لذا انتهت مهلة العرض (التفسير الأكثر ترجيحًا لدي) وبقينا مع مجموعة من الصفحات التي تحتوي فقط على القالب. مع القالب فقط، تكون تلك الصفحات مكررة.” حله: “حاول إعادة هيكلة استدعاءات الجافاسكريبت بحيث يتم تحميل المحتوى (بما في ذلك القالب الهامشي) أولاً.” (تم نقله عبر منشور على لينكد إن، والذي يقاوم التحقق الآلي؛ تعامل معه كثانوي عالي الثقة.)

لاحظ أن إليس يصوغ ذلك بوصفه «التفسير الأرجح لدي»، لا تشخيصًا مؤكدًا، وينبغي أخذ هذا القيد بجدية. لا يمكن تشخيص «انتهاء مهلة العرض» من الأعراض وحدها؛ بل تحتاج إلى دليل من الطلب المباشر، ودليل من الناتج المعروض، وإشارات من Search Console قبل أن تنسب تكرار محتوى مسار بعينه إلى مهلة، بدل خلل أو مورد محظور أو غلاف متطابق فعلًا. ولا توجد مهلة منشورة ثابتة تبني التصميم عليها؛ إذ تقول وثيقة Google الأساسية إن الصفحة “may stay on this queue for a few seconds, but it can take longer than that,” (ترجمة) «قد تبقى في قائمة الانتظار هذه بضع ثوانٍ، لكنها قد تستغرق وقتًا أطول»، من دون تحديد رقم. لذلك لا تخطط وفق مدة مفترضة لقائمة انتظار العرض؛ اجعل المحتوى الأساسي يُحمّل مبكرًا قدر الإمكان مهما استغرق العرض.

الإصلاح: احصل على HTML حقيقي لكل مسار

الإصلاح الكامل له جزءان مستقلان يخلطهما الناس باستمرار:

  1. قابلية عنونة URL — واجهة History API، عناوين URL فريدة لكل مسار، بدون أجزاء.
  2. توفر المحتوى — SSR، أو التقديم المسبق الثابت/SSG، أو إطار عمل وسيط.

افعل فقط #1 وستحصل على عناوين URL نظيفة وقابلة للمشاركة ولكنها جميعًا تعيد نفس القشرة الفارغة. للمسار الذي تريد فعلاً فهرسته، تحتاج إلى كليهما.

هذا ليس تفويضًا عالميًا لإضافة SSR في كل مكان، رغم ذلك. SSR والتقديم المسبق يقللان من اعتمادك على نجاح الزاحف في تنفيذ جافاسكريبت الخاص بك — لا يصبحان إلزاميين بمجرد أن يكون الموقع تقنيًا SPA. قبل اختيار بنية لمسار معين، تحقق من ثلاثة أشياء: ما إذا كان هذا المسار يحتاج إلى الترتيب على الإطلاق (لوحة تحكم داخلية لا تحتاج)، وما الذي يعيده طلب مباشر بدون جافاسكريبت إليه بالفعل (بعض الإعدادات ترسل HTML ذا معنى بالفعل)، وأي الزواحف تحتاج فعلاً إلى إرضائها (جوجل يعرض الجافاسكريبت بشكل موثوق إلى حد ما؛ بينج ومعظم زواحف الذكاء الاصطناعي أقل موثوقية — انظر أدناه). CSR الذي يجتاز هذه الفحوصات بالفعل لا يحتاج إلى أن يصبح SSR فقط لأن الموقع SPA.

العرض من جانب الخادم (SSR)

يقوم الخادم بتشغيل تطبيقك لكل طلب ويعيد HTML مكتمل التكوين لهذا المسار، ثم يقوم العميل “بترطيبه” إلى SPA حي. هذا هو الخيار الأكثر قوة لأن الزاحف يحصل على محتوى كامل في الجلب الأول، دون الحاجة إلى تنفيذ جافاسكريبت.

العرض المسبق الثابت / SSG

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

أو: لا تبنِه يدويًا — استخدم إطار عمل وسيطًا

بالنسبة للمشاريع الجديدة، التوصية الصادقة هي عدم بناء توجيه من جانب العميل يدويًا باستخدام React-Router فقط أو Vue-Router فقط على الإطلاق. إطار عمل فوقي — Next.js، Nuxt، Angular مع حزمة SSR الخاصة به، SvelteKit، Remix — يمنحك SSR/SSG وبيانات وصفية قائمة على المسار بشكل جاهز، مما يتجاوز هذه الفئة الكاملة من المشاكل. (كل واحد من هذه الإطارات لديه دليل متعمق خاص به على هذا الموقع.) كن صريحًا بشأن الجانب الآخر: إضافة SSR إلى تطبيق SPA مبني يدويًا هو عمل هندسي حقيقي — مشروع ترحيل، وليس مجرد تبديل إعدادات.

العرض الديناميكي كحل مؤقت، وليس كوجهة نهائية

يمكنك تقديم لقطة HTML معروضة بشكل منفصل لبرامج الزحف (العرض الديناميكي). كل من Google وBing يقبلانها — Bing “يوصي بالعرض الديناميكي كبديل رائع للمواقع التي تعتمد بشكل كبير على JavaScript” (منقول من مدونة Bing لعام 2018؛ الاقتباسان القصيران التاليان حول قدرات bingbot تم التحقق منهما مباشرة، هذا الاقتباس الأطول لم يتم إعادة التحقق منه بشكل مستقل) — لكن Google واضحة أنها حل مؤقت: “كان العرض الديناميكي حلاً مؤقتًا وليس حلاً طويل الأمد… بدلاً من ذلك، نوصي باستخدام العرض من جانب الخادم، أو العرض الثابت، أو الترويب كحل.” (منقول من وثيقة Google حول العرض الديناميكي؛ الصياغة تطابق ما تم الاستشهاد به بالفعل في دليل JavaScript SEO الأوسع لهذا الموقع.) إنه جسر، وليس بنية أساسية.

History API مقابل توجيه الهاش (#!)

خمس حالات، وليس حالتين

اختبار مسار في تطبيق SPA يصبح مربكًا لأن “هل يعمل” يشمل في الواقع خمس حالات مختلفة وقابلة للتحقق بشكل منفصل:

الحالةما هي
استجابة الخادمالبايتات التي يحصل عليها طلب HTTP جديد بدون JavaScript إلى عنوان URL.
DOM المعروضما يبنيه المتصفح (أو مُصيِّر Googlebot) بعد تنفيذ JavaScript مقابل استجابة الخادم تلك.
معالجة البحثكيف يزحف Google بشكل منفصل إلى استجابة الخادم، ثم يعرض الصفحة لاحقًا، ويفهرس بناءً على كلاهما.
تنقل المتصفح الكامل للمستندطلب HTTP جديد فعلي إلى عنوان URL — الحالة الوحيدة التي يمكنها تغيير استجابة الخادم أو رمز الحالة.
التنقل الناعم في المتصفحانتقال عبر History API (pushState/replaceState) يغير عنوان URL المرئي، وسجل المتصفح، وواجهة المستخدم على الشاشة.

الحالة التي يخلط الجميع بينها: التنقل الناعم يغير عنوان URL وواجهة المستخدم، لكنه لا ينشئ بمفرده استجابة HTTP جديدة أو رمز حالة — يحدث ذلك فقط عند التنقل الكامل (أو طلب مباشر مكافئ، مثل curl). اختبار مسار بالنقر عبر التطبيق من الصفحة الرئيسية يمارس التنقل الناعم؛ اختباره بطلب عنوان URL مباشرة يمارس استجابة الخادم. كلاهما مهم، وقد يختلفان.

ما يمنحك إياه History API

توصية Google لا لبس فيها: “نوصي باستخدام History API لتحميل محتوى مختلف بناءً على عنوان URL في تطبيق SPA.” (في الوثيقة الحية “History API” هو رابط، لذا يستهدف هذا الرابط العميق الجملة التمهيدية.) يتيح لك History API (pushState/replaceState) تغيير عنوان URL المرئي إلى مسار حقيقي قابل للوضع في الإشارات المرجعية — /products، وليس /#/products — دون إعادة تحميل كاملة. هذا يصلح نصف قابلية العنونة: كل عرض الآن لديه عنوان URL يمكن للخادم أن يستجيب له بشكل مختلف.

لماذا تكون عناوين URL ذات الجزء/الهاش غير مرئية للخادم — ولـ Google

لأن الجزء لا يصل أبدًا إلى الخادم (انظر أعلاه)، فإن History API هو الطريقة الوحيدة لإعطاء كل مسار عنوان URL يمكن للخادم تقديمه فعليًا. تضع Google حدًا أدنى لذلك في وثيقتها الأساسية: “لا تستخدم الأجزاء لتحميل محتوى صفحة مختلف. المثال التالي ممارسة سيئة، لأن Googlebot لا يمكنه حل عناوين URL بشكل موثوق.” هذه هي نفس الإرشادات التي كتبتها في مكان آخر — استخدم عناوين URL عادية المظهر مثل /products، وليس عناوين الهاش مثل /#/products، لأن Google لا يمكنه فهرسة عناوين الهاش بشكل موثوق.

إهمال عام 2015، باختصار

انتهى عصر الهاش-بانغ (#!) مع منشور جوجل عام 2015: “لقد تغيرت الأوقات. اليوم، طالما أنك لا تمنع Googlebot من الزحف إلى ملفات JavaScript أو CSS الخاصة بك، فإننا قادرون عمومًا على عرض وفهم صفحات الويب الخاصة بك مثل المتصفحات الحديثة،” و*“يمكنك استخدام History API pushState() لضمان إمكانية الوصول لمجموعة أوسع من المتصفحات (وأنظمتنا).”* هناك فارق دقيق يستحق الاحتفاظ به: لم تقم جوجل بإلغاء فهرسة المواقع القديمة ذات الهاش-بانغ فورًا — “سنقوم عمومًا بالزحف إلى عناوين #! وعرضها وفهرستها” — لكن “لا يزال بإمكاننا المحاولة” ليس “يجب عليك الاستمرار في هذا.”

جعل كل مسار قابلًا للفهرسة بشكل مستقل

العناوين النظيفة وHTML الحقيقي تجعلك تُزحف إليك. للحصول على فهرسة صحيحة، يحتاج كل مسار إلى إشاراته الخاصة.

العنوان الأساسي لكل مسار — وفخ «التوجيه الأكثر تقييدًا»

يحتاج كل مسار إلى rel=canonical خاص به في DOM المُقدَّم. الفخ: إذا تم تضمين canonical مؤقت (أو noindex) في قشرة HTML الخام وكان من المفترض أن تستبدله JavaScript لاحقًا، فقد تحصل على تعارض. تحل جوجل التعارضات بين النسخة الخام والمُقدَّمة من خلال اتخاذ الإشارة الأكثر تقييدًا — كما قلت سابقًا، ستختار جوجل البيانات الأكثر تقييدًا بين HTML والنسخة المُقدَّمة من الصفحة. يمكن أن يؤدي noindex عشوائي أو canonical خاطئ مدمج في القشرة إلى كتم المسار بالكامل بصمت حتى بعد أن “تصلحه” JavaScript.

العناوين والأوصاف التعريفية لكل مسار عبر JavaScript

يجوز تعيين هذه العناصر عبر JavaScript؛ تقول Google مباشرة: “You can use JavaScript to set or change the meta description as well as the <title> element.” (ترجمة) «يمكنك استخدام JavaScript لتعيين وصف meta أو تغييره، وكذلك عنصر <title>». الشرط أن تستقر القيم في DOM المعروض الذي تقيّمه Google، لا أن تظهر لحظةً ثم تختفي. امنح كل صفحة عنوانًا ووصفًا يتغيران مع المسار.

روابط <a href> حقيقية بين المسارات

اجعل الروابط بين المسارات عناصر ارتباط حقيقية بسمات href، لا معالجات نقر على <div>s. تكتشف Google عناوين URL باستخراج hrefs؛ أما <div onClick> الذي يتنقل عبر الموجّه فلا يوفر رابطًا يستخرجه الزاحف. ولا تعتمد على حالة العميل لنقل المحتوى بين عمليات التحميل؛ إذ تقول Google: “WRS does not retain state across page loads: Local Storage and Session Storage data are cleared across page loads. HTTP Cookies are cleared across page loads.” (ترجمة) «لا يحتفظ WRS بالحالة بين عمليات تحميل الصفحات؛ فتُمسح بيانات Local Storage وSession Storage وملفات HTTP Cookies بينها».

إنشاء خريطة موقع لمسارات SPA

لا يوجد تنسيق خاص “خريطة موقع SPA” — إنها مشكلة محاسبية

بروتوكول خريطة الموقع لم يتغير لـ SPAs. العمل الفعلي هو التأكد من أن كل مسار تدرجه بشكل مستقل يتحول إلى HTML حقيقي وفريد ومُقدَّم. خريطة موقع تضم 500 مسار من جانب العميل لا قيمة لها إذا كانت تلك المسارات جميعها تُرجع نفس القشرة. لذا فإن خريطة الموقع تأتي بعد استراتيجية العرض الخاصة بك، وليست بديلاً عنها.

التعامل مع المسارات الديناميكية/المعلمة (/product/:id)

بالنسبة للتطبيقات ذات المسارات المعلمة، لا يمكنك صيانة القائمة يدويًا. يجب أن يعمل مولّد خريطة الموقع على نفس مصدر البيانات الذي يستخدمه التطبيق — سكربت بناء أو نقطة نهاية خادم تُعدّ كل id — بحيث لا تتباعد خريطة الموقع والتطبيق أبدًا. تلك العناوين المُعدَّدة تستحق الإدراج فقط بعد أن تكون SSR’d أو مُسبقة العرض.

إبقاء خريطة الموقع متزامنة مع ما يمكن حله عبر الخادم

أعد توليد خريطة الموقع كجزء من بنائك أو وفقًا لجدول زمني مرتبط بمصدر المحتوى. المسار الذي يُرجع 404s (أو الأسوأ، soft 404s عند 200) لكنه موجود في خريطة موقعك يرسل إشارة جودة سيئة ويهدر ميزانية الزحف.

اختبار ما تراه جوجل فعليًا

لا تفحص عنوان URL واحدًا فقط. بيت القصيد من مشكلة SPA هو أن المسارات يمكن أن تختلف في المتصفح ولكن ليس على الشبكة، لذا اختبر مسارات متعددة على مستوى HTML الخام:

  • جلب HTML الخام لكل مسار باستخدام curl (مع وكيل مستخدم Googlebot حيثما كان ذلك مناسبًا) وتأكد من أن المحتوى فريد لكل URL، وليس الهيكل المشترك.
  • فحص URL في Search Console — قارن HTML المُزحف/المُعرض لعدة مسارات، وتأكد من وجود العنوان والوصف والكنسي الخاص بكل مسار.
  • تأكد من أن مسارات الأخطاء تُرجع الإشارة الصحيحة — يجب أن يعيد عرض “غير موجود” إما توجيهًا إلى حالة خطأ حقيقية أو يحمل noindex في DOM المعروض.

خرافات شائعة حول SEO لتطبيقات الصفحة الواحدة

  • “لا يمكن لجوجل فهرسة تطبيقات الصفحة الواحدة إطلاقًا.” قديم. تشغل جوجل متصفح Chromium دائم التحديث وتقوم عمومًا بعرض محتوى تطبيقات الصفحة الواحدة. المخاطر الحقيقية محددة: أخطاء soft 404s، توجيه الهاش، مهلات العرض، وبرامج الزحف غير التابعة لجوجل (Bing بشكل أقل موثوقية، ومعظم برامج الزحف الذكاء الاصطناعي لا تفعل ذلك إطلاقًا).
  • “إضافة History API يصلح SEO لتطبيقات الصفحة الواحدة.” يصلح قابلية العنونة فقط. إذا كان الخادم لا يزال يُرجع نفس الهيكل لكل مسار، فلا يزال على جوجل تنفيذ JavaScript لرؤية أي شيء.
  • “توجيه الهاش لا يزال يعمل كحل بديل.” مهمل منذ 2015 ويُنصح بعدم استخدامه منذ ذلك الحين.
  • “العرض من جانب العميل هو عقوبة ترتيب.” لا توجد عقوبة مباشرة للعرض من جانب العميل. الضرر غير مباشر — العرض الفاشل/المتأخر، وأخطاء soft 404s، وتجميع النسخ المكررة الناتج عن مهلات العرض يقلل مما يُفهرس.
  • “العرض المسبق للروبوتات هو تمويه.” ليس كذلك عندما يتطابق المحتوى مع ما يراه المستخدمون في النهاية — فقط متى/أين يختلف العرض، وليس المحتوى.
  • “تحتاج إلى مولد خريطة موقع خاص لتطبيقات الصفحة الواحدة.” لا يوجد تنسيق خاص؛ العمل هو جعل كل مسار مدرج يتحول إلى HTML حقيقي.

الأسئلة الشائعة

هل يمكن لجوجل فهرسة تطبيق صفحة واحدة؟ نعم، إذا كان كل مسار يتحول إلى HTML حقيقي وفريد (عبر SSR/العرض المسبق) على URL حقيقي. غالبًا لا تفعل تطبيقات الصفحة الواحدة التي تعتمد على العميل فقط ذلك.

هل أحتاج إلى SSR، أم أن العرض من جانب العميل مقبول أحيانًا؟ يمكن أن يعمل CSR للمحتوى الذي لا يحتاج إلى الترتيب، ولكن لأي شيء تريد فهرسته بشكل موثوق، قم بالعرض المسبق أو SSR — لا تراهن على أن المُعرض سينفذ JavaScript في الوقت المناسب.

هل توجيه الهاش (#!) سيء لـ SEO؟ نعم — الجزء لا يصل أبدًا إلى الخادم، لذا لا يمكن لجوجل حل هذه العناوين بشكل موثوق. استخدم History API.

هل يحتاج كل مسار إلى وسم كنسي خاص به؟ نعم، في DOM المعروض — وتأكد من عدم وجود شيء أكثر تقييدًا (noindex عشوائي أو كنسي خاطئ) في الهيكل الخام.

هل خدمة العرض المسبق تمويه؟ لا، بشرط أن يتطابق المحتوى المُقدم للروبوتات مع ما يراه المستخدمون.

هل يجب أن أستخدم إطار عمل فوقي بدلاً من بناء التوجيه بنفسي؟ للبناء الجديد، عادةً نعم — Next.js/Nuxt/Angular-SSR/SvelteKit تمنحك SSR/SSG وبيانات وصفية لكل مسار مجانًا.

لماذا يُرجع تطبيق الصفحة الواحدة الخاص بي 200 لصفحات غير موجودة؟ لأن الموجّه من جانب العميل يحتفظ بحالة 200 الأصلية للتنقلات الافتراضية. أصلح ذلك بإعادة توجيه JavaScript إلى حالة خطأ حقيقية أو noindex معروض.

Add an expert note

Pin an expert quote

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