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

هل لا تستخدم ميزة العرض من جهة الخادم ولكنك تريد تسريع أداء موقعك الإلكتروني المستند إلى 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. إذا كنت تستخدِم ميزة تقسيم الرموز البرمجية على مستوى المكوّن ضمن أيّ مسار، يجب توخّي الحذر من عدم عرض حالة التحميل مسبقًا للمستخدمين. يتناولملف react-snap README هذه المسألة بمزيد من التفصيل.