تحسين محركات البحث لمواقع React

يعرض React الصفحات من جهة العميل افتراضياً، لذلك ترى برامج الزحف غلافاً فارغاً إلى أن تعمل JavaScript. إليك كيف تعالج Google تطبيقات React فعلياً، وأي استراتيجية عرض تختار، وكيف تصلح التوجيه والبيانات الوصفية وفخ المحتوى المكرر الناتج عن انتهاء مهلة العرض.

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

React ليست سيئة لتحسين محركات البحث، لكن العرض الافتراضي من جهة العميل هو المشكلة. في CRA وVite + React يرسل الخادم غلافاً فارغاً ويبني المتصفح الصفحة، فلا ترى برامج الزحف شيئاً حتى تعمل JavaScript. تستطيع Google عرض React عبر Web Rendering Service، لكن العرض يدخل طابوراً وقد يتأخر أو تنتهي مهلته؛ وقد عرض Gary Illyes حالات تركت فيها المهلة صفحات تحتوي على القالب المشترك فقط فصُنفت مكررة. تختلف عقود العرض لدى زواحف الذكاء الاصطناعي حسب الموفّر، لذلك يضيف محتوى CSR فقط خطر نقص التغطية. والحل هو استراتيجية العرض؛ إذ يضع SSR أو SSG، والأسهل عادة عبر Next.js أو Remix، المحتوى في HTML الأولي، ثم تتم إماهته باستخدام hydrateRoot لا createRoot كي يتطابق خرج الخادم والعميل تماماً. وبعد ذلك استخدم History API وروابط <a href> حقيقية ورموز حالة صحيحة وبيانات وصفية مناسبة للإصدار؛ ينقل React 19 وسوم <title>/<meta>/<link> أصلياً، وإلا فاستخدم react-helmet-async ولا تستخدم react-helmet الأصلي المتروك.

الخلاصة — مشكلة React مع تحسين محركات البحث ليست React نفسها، بل العرض الافتراضي من جهة العميل. يرسل CRA وVite + React غلافاً فارغاً ويبنيان DOM في المتصفح، لذلك لا يحتوي HTML الخام الذي يجلبه الزاحف على محتوى. تستطيع Google عرضه عبر Web Rendering Service المبني على Chromium دائم التحديث، لكن العرض يدخل طابوراً منفصلاً وقد يتأخر وقد تنتهي مهلته. وقد وثق Gary Illyes أن مهلات العرض تترك صفحات لا تحتوي إلا على القالب المشترك ثم تُصنف مكررة. يعرض Bing JavaScript بدرجة أقل موثوقية، ويختلف عرض زواحف الذكاء الاصطناعي حسب الموفّر. والحل هو استراتيجية العرض: يضع SSR أو SSG، والأسهل عبر Next.js أو Remix، المحتوى في HTML الأولي. وإذا كنت تميه ترميزاً معروضاً على الخادم، فاستخدم hydrateRoot لا createRoot وتعامل مع أي اختلاف بين الخادم والعميل كخطأ لا كتحذير ينبغي إخفاؤه. ثم استخدم توجيه History API لا عناوين التجزئة، وروابط <a href> حقيقية. ولبيانات <head> الوصفية، ينقل React 19 وسوم <title> و<meta> و<link> أصلياً؛ أما في React 18 أو للاحتياجات المتقدمة فاستخدم react-helmet-async، ولا تستخدم react-helmet الأصلي المتروك. اضبط رموز حالة HTTP الصحيحة. لا تمنح SSR مكافأة ترتيب، بل تجعل المحتوى قابلاً للفهرسة بصورة موثوقة.

ما الذي يجعل React صعبة فعلياً لتحسين محركات البحث

React مكتبة JavaScript قائمة على المكونات، وتعمل خارج الصندوق، عبر Create React App أو Vite + React، من جهة العميل. يعيد الخادم مستنداً شبه فارغ، ومن أشهر صوره <div id="root"></div>، مع حزمة JavaScript، ثم ينفذ المتصفح JavaScript لبناء DOM. قارن ذلك بصفحة معروضة على الخادم، مثل WordPress أو تطبيق Rails، حيث يصل HTML الكامل، بما فيه المحتوى والعناوين والروابط، في الاستجابة الأولى.

لذلك فالسؤال الذي يحسم كل شيء هو: ما الموجود في HTML الخام قبل تشغيل أي JavaScript؟ في تطبيق React افتراضي تكون الإجابة «لا شيء تقريباً». انقر بزر الفأرة الأيمن واختر View Source في تطبيق CRA وسترى الغلاف لا المحتوى. وهذا بالضبط ما يحصل عليه الزاحف في أول جلب.

ولتحديد المسؤولية بدقة: مكتبة React ليست محصورة في CSR. يوفر React DOM العرض من جهة العميل عبر createRoot، والعرض على الخادم عبر واجهات متدفقة وثابتة، وواجهات الإماهة؛ فالمكتبة تدعم ذلك كله. مشكلة الغلاف الفارغ خاصية في سلسلة الأدوات الافتراضية، أي Create React App أو Vite + React من دون خادم، التي توصل واجهات العميل فقط ولا توفر شيئاً يعرض HTML على الخادم. بدّل سلسلة الأدوات إلى Next.js أو Remix أو واجهات العرض الخادمي في React نفسها، وسترسل المكتبة نفسها HTML كاملاً في الاستجابة الأولى.

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

كيف تعالج Google تطبيق React فعلياً

تتعامل Google مع JavaScript في ثلاث مراحل: الزحف ← العرض ← الفهرسة. يجلب Googlebot عنوان URL، ثم يبني Web Rendering Service (WRS)، وهو نسخة دائمة التحديث من Chromium ومحرك Chrome نفسه، DOM المعروض لاحقاً، وبعدها يُفهرس الناتج وتُستخرج روابطه. Evidence for this claim Google processes JavaScript pages through crawling, rendering, and indexing using its Web Rendering Service. Scope: Google Search rendering behavior. Confidence: high · Verified: Google: JavaScript SEO basics

الفارق المهم هو وقت العرض. لأنه كثيف الموارد، يدخل العرض طابوراً منفصلاً عن الزحف الأولي. وصف Martin Splitt التدفق بوضوح: “we do an HTTP request, and we get something back … some barebone HTML and all it does is load the JavaScript and run the JavaScript. Then, this HTML … goes into rendering. Rendering runs JavaScript — boom!, a lot of content happens that wasn’t there before.” (ترجمة) «نجري طلب HTTP ونستقبل شيئاً، ربما HTML أساسياً لا يفعل سوى تحميل JavaScript وتشغيلها. ثم يدخل هذا HTML في العرض. يشغّل العرض JavaScript، وفجأة يظهر كثير من المحتوى الذي لم يكن موجوداً من قبل.» في صفحة React بنمط CSR تكون هذه «الطفرة» هي صفحتك كلها؛ فلا يوجد شيء منها حتى تعمل خطوة العرض.

وثمة تحذير مهم: لا تبالغ في الاعتماد على نموذج «موجتي الفهرسة» القديم. فقد تراجع Splitt نفسه عنه وسمّى الموجة “an oversimplification.” (ترجمة) «تبسيطاً مفرطاً». ليست الخلاصة أن هناك «موجة ثانية» رسمية ذات توقيت محدد، بل إن العرض خطوة مستقلة قابلة للتأجيل والفشل، وأن CSR يضع 100% من محتواك على الجانب الخطأ منها.

حقيقتان أخريان عن العارض تؤذيان تطبيقات React تحديداً:

  • إنه عديم الحالة. لا يحتفظ Googlebot بـlocalStorage أو sessionStorage أو ملفات تعريف الارتباط بين تحميلات الصفحات. وأي محتوى أو توجيه يعتمد على حالة العميل غير مرئي للزاحف.
  • يمكنه الاستسلام. يفرض العارض مهلة. فإذا كان تحميل المحتوى الرئيسي بطيئاً، بسبب حزم كبيرة أو سلسلة طلبات API، فقد ينتهي العرض قبل وصول المحتوى وتفهرس Google الصفحة غير المكتملة.

فخ انتهاء مهلة العرض ولماذا ينشئ صفحات مكررة

نادراً ما يُشرح وضع الفشل هذا جيداً، وهو الأكثر ضرراً لتطبيقات React. وصفه Gary Illyes مباشرة: “I have a bunch of emails in my inbox where the issue is that the centerpiece took forever to load, so rendering timed out … and we were left with a bunch of pages that only had the boilerplate. With only the boilerplate, those pages are dups.” (ترجمة) «لدي رسائل كثيرة كانت مشكلتها أن المحتوى المركزي استغرق وقتاً طويلاً جداً للتحميل، فانتهت مهلة العرض، وبقيت صفحات لا تحتوي إلا على القالب المشترك. ومع القالب وحده تصبح تلك الصفحات مكررة.»

تتبع ما يعنيه ذلك لتطبيق React بنمط CSR. يحمل الرأس والتنقل والتذييل، وهي القالب المشترك، بسرعة. أما محتوى الصفحة الفعلي الذي يميز كل عنوان URL فيُجلب ويُعرض عبر JavaScript ويصل ببطء. تنتهي مهلة العرض، فلا يبقى لدى Google سوى الرأس والتنقل والتذييل في كل عنوان URL. تبدو كل الصفحات متطابقة فتعلّمها Google كمكررات في Search Console.

أما إصلاح Illyes نفسه فهو الجزء القابل للتنفيذ: “Try to restructure the js calls such that the content (including marginal boilerplate) loads first and see if that helps.” (ترجمة) «حاول إعادة هيكلة استدعاءات JavaScript بحيث يُحمّل المحتوى، بما فيه القالب الهامشي، أولاً، ثم انظر هل يساعد ذلك.» لكن الحل الأكثر دواماً هو ألا تعتمد على خطوة العرض لمحتواك الرئيسي، أي استخدام SSR أو SSG.

استراتيجيات العرض في React

هذا القرار الأكثر تأثيراً. الخيارات، من الأسوأ إلى الأفضل تقريباً لتحسين محركات البحث:

  • CSR، React الافتراضية. يرسل الخادم الغلاف ويبني المتصفح كل شيء. يتأخر المحتوى بسبب طابور العرض ويتعرض للمهلة. وهو الأعلى مخاطرة لتحسين محركات البحث، لكنه مناسب للوحات التحكم المسجلة التي لا تريد فهرستها. Evidence for this claim Client-only React rendering constructs UI in the browser; server rendering APIs produce HTML before browser hydration. Scope: React rendering mechanics; SEO impact depends on what the initial response contains. Confidence: high · Verified: React: hydrateRoot React: Server APIs
  • العرض المسبق. عرض في وقت البناء من دون إطار SSR كامل؛ تزحف أدوات مثل react-snap أو خدمة عرض مسبق إلى تطبيقك وتحفظ HTML ثابتاً. وهو أخف ويناسب المواقع الأبسط والثابتة في معظمها.
  • SSG، توليد الموقع الثابت. يُبنى HTML مرة في وقت النشر ويُقدّم كملفات ثابتة. هو الأسرع والمحتوى حاضر دائماً في HTML الخام، لكنه محدود للمحتوى شديد الديناميكية أو الخاص بالمستخدم، وقد تطول أوقات البناء للمواقع الكبيرة.
  • SSR، العرض من جهة الخادم. ينفذ الخادم React لكل طلب ويرسل HTML كاملاً. يتاح المحتوى فوراً للزواحف ويظل حديثاً، لكنه يتطلب خادم Node.js وقد يرفع TTFB قليلاً.
  • الهجين أو ISR، التجديد الثابت التزايدي. ميزة في Next.js تعيد توليد الصفحات الثابتة في الخلفية، فتوفر سرعة الثبات مع تحديث دوري.
الاستراتيجيةهل المحتوى في HTML الأولي؟مخاطر SEOالأنسب لـ
CSR، React خاملاالأعلىلوحات تحكم مسجلة وتطبيقات غير مفهرسة
العرض المسبقنعم، في وقت البناءمنخفضةمواقع صغيرة وثابتة غالباً
SSGنعم، في وقت البناءالأدنىالمدونات والوثائق والتسويق
SSRنعم، لكل طلبمنخفضةمحتوى حديث وديناميكي
ISR أو الهجيننعممنخفضةمحتوى يتغير كل ساعة أو يوم

وهناك استراتيجية ينبغي تجنبها في المشاريع الجديدة: العرض الديناميكي، أي اكتشاف وكيل مستخدم الزاحف وتقديم نسخة معروضة مسبقاً له بينما يحصل المستخدمون على CSR. تسميه Google الآن “a workaround and not a long-term solution” (ترجمة) «حلاً التفافياً لا حلاً طويل الأمد»، وتقول إنه “creates additional complexities and resource requirements,” (ترجمة) «ينشئ تعقيدات ومتطلبات موارد إضافية»، وتوصي بدلاً منه بالعرض من جهة الخادم أو العرض الثابت أو الإماهة. أوصى Bing بالعرض الديناميكي في 2018، لكن الإرشاد قديم؛ فمنذ 2019 يعرض Bingbot عبر Microsoft Edge وChromium، ويبقى SSR أو SSG الاختيار الصحيح.

ينبغي أيضاً إنهاء أسطورة أن SSR تمنح دفعة ترتيب. قال John Mueller: “there are no SEO ranking bonuses for implementing it one way or another” (ترجمة) «لا توجد مكافآت ترتيب في تحسين محركات البحث لاختيار طريقة تنفيذ دون أخرى»، فالطرق المختلفة “just different ways of making the content indexable.” (ترجمة) «مجرد طرق مختلفة لجعل المحتوى قابلاً للفهرسة». قيمة SSR هي موثوقية الفهرسة، وغالباً تحسين Core Web Vitals بفضل First Contentful Paint أسرع، لا رافعة ترتيب سحرية.

يجب أن تتطابق الإماهة تماماً: هذا حد للخطأ لا تقنية SEO

يسلّم SSR وSSG المتصفح HTML يحتوي على محتواك بالفعل. ثم يتعين على React الاتصال بذلك الترميز على العميل، وهذا يستخدم واجهة مختلفة عن العرض العادي من جهة العميل:

  • createRoot يعرض React في عقدة DOM من الصفر ولا يتوقع ترميزاً موجوداً. استخدمه لتطبيقات CSR فقط.
  • hydrateRoot يتصل بـHTML سبق أن ولّده react-dom/server، ويتوقع أن ينتج العرض الأول للعميل خرجاً مطابقاً لما أرسله الخادم. إذا كنت تستخدم SSR أو SSG فأنت تريد hydrateRoot لا createRoot. إن استدعاء createRoot على ترميز معروض على الخادم يجعل React يتخلص منه ويعيد العرض من الصفر، فيهدر بالضبط فائدة تحسين محركات البحث التي أعددت SSR أو SSG لتحقيقها.
Evidence for this claim hydrateRoot attaches React to HTML previously generated by React on the server; the initial client output should match the server output. Scope: hydration Confidence: high · Verified: hydrateRoot

يمثل عدم التطابق بين خرج الخادم والعميل خطراً حقيقياً في تطبيقات React التي تصلح SEO، مثل Date.now() في عنوان أو تنسيق يعتمد على المنطقة أو فرع if (typeof window !== 'undefined'). توضح وثائق React ما يحدث: تحذر من عدم التطابق في التطوير، لكن “there are no guarantees that attribute differences will be patched up in case of mismatches.” (ترجمة) «لا توجد ضمانات بأن اختلافات السمات ستُصحح عند عدم التطابق». والإرشاد هو معاملتها كأخطاء وإصلاحها، لا إخفاء التحذير وافتراض تكافؤ المحتوى. ولتحسين محركات البحث، لا تفترض تطابق المحتوى والبيانات الوصفية مع ما أرسله الخادم لأن الصفحة تبدو صحيحة في المتصفح. قارن HTML الخادم مباشرة بـDOM بعد الإماهة، أو استخدم فحص View Source مقابل Inspect Element السريع أدناه.

React Router وبنية عناوين URL

يدير React Router التنقل في المتصفح من دون رحلات إلى الخادم، وهذا مناسب لتحسين محركات البحث إذا ضُبط جيداً:

  • استخدم History API لا توجيه التجزئة. يستخدم BrowserRouter الدالة pushState وينتج عناوين نظيفة قابلة للزحف مثل /products. ينتج HashRouter عناوين مثل /#/products لا تستطيع Google حلها بصورة موثوقة؛ إذ أُلغي مخطط زحف AJAX القديم. استخدم History API.
  • يجب أن يتعامل الخادم مع هذه العناوين أيضاً. مع توجيه History API تحتاج كل «صفحة» إلى عنوان حقيقي يستجيب له الخادم، وهو ضروري لـSSR ولكي لا يعيد الوصول المباشر أو تحديث /products خطأ 404.
  • يعرض <Link> رابطاً حقيقياً. ينتج مكوّن <Link> في React Router عنصراً <a href> قابلاً للزحف. أما التنقل المبني على onClick من دون رابط فغير قابل للزحف؛ إذ تتبع Google روابط <a href> الحقيقية فقط.

إدارة البيانات الوصفية: react-helmet وreact-helmet-async ووسوم React 19 الأصلية

حتى React 18 لم يكن React يحدّث <head> أصلياً عند تغير المسار؛ وكان يلزم تعيين <title> والوصف وcanonical ووسوم Open Graph وTwitter لكل مسار بواسطة مكتبة. غيّر React 19 ذلك: تستطيع المكونات عرض <title> و<meta> و<link> مباشرة، وينقلها React إلى <head> من تلقاء نفسه، في التطبيقات العميلية وSSR المتدفق وServer Components. وReact 19.2 هو الإصدار المستقر الحالي في منتصف 2026، لذلك ينطبق ذلك على التطبيقات ذات الإصدار الحالي.

تعتمد الإجابة الصحيحة على إصدار React وما تحتاج إليه:

  • React 19، تطبيق مستقل ووسوم أساسية فقط. اعرض <title> و<meta> و<link> في مكوناتك مباشرة، ولا تحتاج إلى مكتبة.
  • React 19، لكنك تحتاج htmlAttributes أو bodyAttributes أو تسلسل context في SSR أو onChangeClientState أو prioritizeSeoTags أو titleTemplate. لا يغطي النقل الأصلي هذه الميزات؛ فاستخدم react-helmet-async. وتوضح وثائقه أنك قد لا تحتاج إلى الحزمة في React 19 إن لم تكن لديك تلك الاحتياجات.
  • React 18 أو أقدم، تطبيق مستقل. لا يوجد النقل الأصلي بعد؛ فاستخدم react-helmet-async. إنه مصان بنشاط، في الإصدار الرئيسي 3، ويكتشف إصدار React وقت التشغيل ويدعم SSR.
  • react-helmet الأصلي. لا تستخدمه مع أي إصدار. لم يعد مصاناً ولم يصدر له تحديث منذ 2020، وله عيوب مع العرض المتزامن في React 18.
  • تطبيقات Next.js. استخدم Metadata API في Next، أي تصدير metadata أو generateMetadata في App Router، بصرف النظر عن إصدار React. لا تضف Helmet ولا تعتمد على النقل الأصلي للوسوم؛ فالإطار يملك المستند في تطبيق Next.js.

تنطبق قاعدة موثوقية واحدة مهما كان اختيارك: البيانات الوصفية الموجودة في HTML أفضل من البيانات المحقونة عبر JavaScript. ووسم canonical المحقون من جهة العميل أقل موثوقية بكثير من الموجود في HTML المعروض على الخادم، وهذا حجة أخرى لـSSR أو SSG.

زواحف الذكاء الاصطناعي تجعل الأمر ملحاً

التطور في 2026 هو أن سلوك العرض لدى GPTBot من OpenAI وClaudeBot من Anthropic وPerplexityBot وغيرهم خاص بكل موفّر وإصدار. يرسل تطبيق React بنمط CSR الغلاف الفارغ نفسه لكل زاحف كما في أول جلب لـGooglebot، ولا تثبت وثائق الموفّرين الحالية وجود خطوة عرض مشتركة تملأه. ومع نمو المحركات التوليدية كسطح اكتشاف، لا يعود SSR أو SSG شأناً خاصاً بـGoogle؛ إذ يزيد HTML الخام التغطية من دون افتراض قيد عالمي على الزواحف. ويغطي موضوع headless CMS هذا الواقع بمزيد من العمق.

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

لا تثق بمتصفحك؛ يعرض DevTools Inspector DOM بعد العرض، أي بعد JavaScript، وهو بالضبط ما لا يراه الزاحف الذي لا يشغلها. استخدم الأدوات الصحيحة:

  • View Source مقابل Inspect Element. الأول هو HTML الخام قبل JavaScript، والثاني DOM المعروض. إذا كان المحتوى في Inspect وغير موجود في View Source فهو يعتمد على JavaScript.
  • URL Inspection Tool في Search Console. الاختبار الأكثر موثوقية. شغّل اختباراً مباشراً وافحص HTML المعروض ولقطة الشاشة وموارد الصفحة ورسائل وحدة التحكم لترى ما عرضته Google وما فشل تحميله.
  • Rich Results Test. فحص سريع لـHTML المعروض من دون التحقق من ملكية الموقع.
  • عطّل JavaScript في DevTools وأعد التحميل لمحاكاة سريعة لزاحف لا ينفذ JavaScript، وهو بديل تقريبي لما تراه زواحف الذكاء الاصطناعي.
  • تقرير التغطية في Search Console. قد تشير حالة “Discovered, currently not indexed” (ترجمة) «تم اكتشاف الصفحة ولم تتم فهرستها حالياً» إلى تراكم طابور العرض، وقد تشير مجموعات التكرار إلى فخ انتهاء المهلة.
  • زواحف تعرض JavaScript. يعرض Ahrefs Site Audit وScreaming Frog في وضع JavaScript الصفحات على نطاق واسع لتستطيع مقارنة HTML الخام بالمعروض عبر الموقع.

Next.js وRemix: الإجابة العملية

إذا كان SEO مهماً وكنت تستخدم React بنمط CSR الخام، فعادة يكون الانتقال إلى إطار يعرض على الخادم هو الصحيح. صُمم Next.js لذلك، ويوفر SSR وSSG وISR وApp Router وMetadata API مدمجة وتقسيم الشفرة وتحسين الصور. أما Remix فهو بديل قائم على معايير الويب، مبني على fetch وRequest وResponse، ويستخدم SSR افتراضياً ويدعم التحسين التدريجي بقوة. لدى Next.js شرح مستقل؛ أختصر هنا قصداً. النقطة الأضيق لـReact SEO هي أن الإطار ينقل محتواك من خطوة العرض المحصورة في المتصفح إلى HTML الأولي.

تكون React جيدة لتحسين محركات البحث عندما تعامل العرض كقرار معماري لا كفكرة لاحقة. اختر SSR أو SSG لكل ما يحتاج إلى الترتيب، وحافظ على صدق الروابط والتوجيه، وأدر البيانات الوصفية لكل مسار، ودع أدوات Google نفسها، لا متصفحك، تخبرك بما عُرض فعلاً.

Add an expert note

Pin an expert quote

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