عرض المسارات مسبقًا باستخدام ميزة "تفاعل الانطباق"

هل العرض من جهة الخادم ليس من جهة الخادم ولكنّك تريد تسريع أداء موقعك الإلكتروني في React؟ جرِّب ميزة "العرض المُسبَق".

react-snap هي مكتبة تابعه لجهة خارجية تعرض الصفحات على موقعك الإلكتروني مسبقًا في ملفات HTML ثابتة. ويمكن أن يؤدي ذلك إلى تحسين وقت عرض المحتوى لأول مرة في تطبيقك.

في ما يلي مقارنة بين التطبيق نفسه مع العرض المسبق المُحمّل على اتصال 3G وجهاز جوّال تمت محاكاته وبدونه:

مقارنة بين عمليات التحميل جنبًا إلى جنب ويتم تحميل الإصدار الذي يستخدم العرض المسبق بسرعة 4.2 ثوانٍ.

ما الفائدة من ذلك؟

تتمثل المشكلة الرئيسية في الأداء المتعلّقة بالتطبيقات الكبيرة المكوّنة من صفحة واحدة في أنّه على المستخدم الانتظار إلى أن يكتمل تحميل حِزم JavaScript التي تشكّل الموقع الإلكتروني، لكي يتمكّن من الاطّلاع على أي محتوى حقيقي. كلما زاد حجم الحزم، طالت مدة انتظار المستخدم.

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

العرض المُسبَق هو تقنية منفصلة أقل تعقيدًا من عرض الخادم، ولكنه يقدّم أيضًا طريقة لتحسين أوقات "العرض الأوّل" في تطبيقك. يتم استخدام متصفّح بلا واجهة مستخدم لإنشاء ملفات HTML ثابتة لكل مسار أثناء وقت الإنشاء. يمكن بعد ذلك إرسال هذه الملفات مع حِزم JavaScript المطلوبة لتطبيق .

react-snap

يستخدم react-snap Puppeteer لإنشاء ملفات HTML معروضة مسبقًا لمسارات مختلفة في تطبيقك. للتصعيد، عليك أولاً تثبيته كتبعية تطوير:

npm install --save-dev react-snap

بعد ذلك، أضِف نصًا برمجيًا postbuild في package.json:

"scripts": {
  //...
  "postbuild": "react-snap"
}

سيؤدي ذلك إلى تنفيذ الأمر react-snap تلقائيًا في كل مرة يتم فيها إنشاء إصدار جديد من التطبيقات (npm build).

آخر شيء سيتعين عليك القيام به هو تغيير طريقة تشغيل التطبيق. غيِّر ملف src/index.js إلى ما يلي:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
const rootElement = document.getElementById("root");

if (rootElement.hasChildNodes()) {
  ReactDOM.hydrate(<App />, rootElement);
} else {
  ReactDOM.render(<App />, rootElement);
}

بدلاً من استخدام ReactDOM.render فقط لعرض عنصر React الجذر مباشرةً في DOM، يتحقّق هذا الإجراء لمعرفة ما إذا كانت هناك أي عقد فرعية متوفّرة لتحديد ما إذا تم عرض محتوى HTML مسبقًا (أو عرضه على الخادم). وفي هذه الحالة، يتم استخدام ReactDOM.hydrate بدلاً من ذلك لإرفاق أدوات استماع الأحداث إلى ملف HTML الذي سبق إنشاؤه بدلاً من إنشائه من جديد.

سيؤدي إنشاء التطبيق الآن إلى إنشاء ملفات HTML ثابتة كحمولات لكل مسار يتم الزحف إليه. يمكنك الاطّلاع على شكل الحمولة البرمجية لملف HTML من خلال النقر على عنوان URL لطلب HTML ثم النقر على علامة التبويب المعاينات ضمن "أدوات مطوّري البرامج في Chrome".

المقارنة قبل وبعد. تعرِض اللقطة التي تم التقاطها بعد ذلك المحتوى الذي تم عرضه.

وميض من محتوى غير نمطي

على الرغم من أنّ صفحات HTML الثابتة يتم عرضها الآن على الفور تقريبًا، إلا أنّها تظل بدون تنسيق تلقائيًا، ما قد يتسبب في ظهور مشكلة "وميض محتوى بدون تنسيق" (FOUC). ويمكن ملاحظة ذلك بشكل خاص إذا كنت تستخدِم مكتبة CSS-in-JS لإنشاء أدوات الاختيار، لأنّ حِزمة JavaScript يجب أن تنتهي من التنفيذ قبل أن يتم تطبيق أي أنماط.

للمساعدة في منع حدوث ذلك، يمكن تضمين ملف CSS الحيوي أو الحد الأدنى من ملف CSS الذي يلزم لعرض الصفحة الأولية مباشرةً في <head> مستند HTML. يستخدم react-snap مكتبة أخرى تابعة لجهة خارجية، minimalcss، لاستخراج أي ملفات CSS مهمة للمسارات المختلفة. يمكنك تفعيل هذه الميزة من خلال تحديد العناصر التالية في ملف package.json:

"reactSnap": {
  "inlineCss": true
}

عند إلقاء نظرة على معاينة الاستجابة في "أدوات مطوّري البرامج في Chrome"، ستظهر الآن الصفحة المنسَّقة مع تضمين ملفات CSS المهمة.

مقارنة بين الصور قبل وبعد التعديل تُظهر اللقطة التي تم التقاطها بعد ذلك أنّه تم عرض المحتوى وتنسيقه بسبب CSS المضمّن.

الخاتمة

إذا لم تكن مسارات العرض من جهة الخادم في تطبيقك، يمكنك استخدام react-snap لعرض محتوى HTML ثابت مسبقًا للمستخدمين.

  1. قم بتثبيتها كتبعية للتطوير والبدء بالإعدادات الافتراضية فقط.
  2. ويمكنك استخدام خيار inlineCss التجريبي لتضمين محتوى CSS المهم إذا كان مناسبًا لموقعك الإلكتروني.
  3. إذا كنت تستخدِم ميزة تقسيم الرموز البرمجية على مستوى المكوّنات ضمن أيّ مسارات، يجب توخّي الحذر من عدم عرض حالة التحميل مسبقًا للمستخدمين. يتناولملف react-snap README هذه المسألة بمزيد من التفصيل.