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

هل لا تستخدم ميزة المعالجة من جهة الخادم ولكنك تريد تسريع أداء موقعك الإلكتروني المستند إلى 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.