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

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

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

في ما يلي مقارنة بين التطبيق نفسه مع ميزة "العرض المُسبَق" وبدونها، وهو محمَّل على اتصال شبكات الجيل الثالث وجهاز جوّال تمّت محاكاتهما:

مقارنة بين عمليات التحميل جنبًا إلى جنب يتم تحميل الإصدار الذي يستخدم ميزة "العرض المُسبَق" بشكل أسرع بمقدار 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. ثبِّت الإصدار كعنصر تابع لتطوير التطبيق وابدأ باستخدام الإعدادات default فقط.
  2. استخدِم الخيار التجريبي inlineCss لتضمين ملف CSS المهم إذا كان يعمل بشكلٍ سليم على موقعك الإلكتروني.
  3. إذا كنت تستخدِم ميزة "تقسيم الرموز البرمجية" على مستوى المكوّن ضمن أيّ مسار، يجب توخّي الحذر من عرض حالة التحميل مسبقًا للمستخدمين. يمكنك الاطّلاع على مزيد من التفاصيل فيملف README الذي يتضمّن react-snap.