تضمين المورد في أُطر عمل JavaScript

تحسين سرعة عرض أكبر محتوى مرئي في منظومة JavaScript المتكاملة

في إطار مشروع Aurora، تعمل Google على تطوير أطر عمل الويب الشائعة لضمان أدائها بشكل جيد وفقًا لمؤشرات أداء الويب الأساسية. تم بالفعل تضمين الخط في Angular وNext.js، وذلك هو موضّح في الجزء الأول من هذه المقالة. أما التحسين الثاني الذي سنتناوله، فهو تضمين CSS المهم والذي يتم الآن تفعيله تلقائيًا في Angular CLI، ويجري العمل حاليًا على تنفيذ Nuxt.js.

تضمين الخط

بعد تحليل مئات التطبيقات، توصّل فريق Aurora إلى أنّ مطوّري البرامج غالبًا ما يدرجون الخطوط في تطبيقاتهم من خلال الإشارة إليها في العنصر <head> ضمن index.html. فيما يلي مثال على كيف سيبدو ذلك عند تضمين أيقونات Material:

<!doctype html>
<html lang="en">
<head>
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  ...
</html>

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

/* fallback */
@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/font.woff2) format('woff2');
}

.material-icons {
  /*...*/
}

لاحِظ كيف يشير تعريف font-face إلى ملف خارجي تتم استضافته على fonts.gstatic.com. عند تحميل التطبيق، يتعين على المتصفح أولاً تنزيل ورقة الأنماط الأصلية المشار إليها في رأس الصفحة.

صورة توضح كيف يجب على موقع الويب تقديم طلب إلى الخادم وتنزيل ورقة الأنماط الخارجية
أولاً، يُحمِّل الموقع الإلكتروني ورقة أنماط الخط.

بعد ذلك، ينزّل المتصفّح ملف woff2، ثم يتمكّن في النهاية من مواصلة عرض التطبيق.

صورة تعرض الطلبَين اللذين تم تقديمهما، أحدهما لورقة أنماط الخط والآخر لملف الخط
بعد ذلك، يتم إجراء طلب لتحميل الخط.

تتوفّر فرصة للتحسين من خلال تنزيل ورقة الأنماط الأولية في وقت الإصدار وتضمينها في index.html. يؤدي هذا الإجراء إلى تخطي عملية ذهاب وعودة بالكامل إلى شبكة توصيل المحتوى (CDN) في وقت التشغيل، ما يقلّل من وقت الحظر.

عند إنشاء التطبيق، يتم إرسال طلب إلى شبكة توصيل المحتوى (CDN)، ويؤدي ذلك إلى جلب ورقة الأنماط وتضمينها في ملف HTML، ما يؤدي إلى إضافة <link rel=preconnect> إلى النطاق. باستخدام هذا الأسلوب، سنحصل على النتيجة التالية:

<!doctype html>
<html lang="en">
<head>
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin >
  <style type="text/css">
  @font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/font.woff2) format('woff2');}.material-icons{/*...*/}</style>
  ...
</html>

تتوفر الآن إمكانية تضمين الخط في Next.js وAngular

عندما ينفّذ مطوِّرو أُطر العمل عملية التحسين في الأدوات الأساسية، تسهّل على التطبيقات الحالية والجديدة تفعيلها، ما يؤدي إلى تحسين المنظومة المتكاملة بأكملها.

يتم تفعيل هذا التحسين تلقائيًا من الإصدار 10.2 من Next.js والإصدار 11 من Angular. كلاهما يدعم تضمين خطوط Google وAdobe. من المتوقع أن تقدم Angular الإصدار الأخير في الإصدار 12.2.

يمكنك العثور على تنفيذ تضمين الخط في Next.js على GitHub، ومشاهدة الفيديو الذي يشرح هذا التحسين في سياق Angular.

تضمين محتوى CSS المهم

وتشمل التحسينات الأخرى تحسين مقياسَي سرعة عرض أكبر محتوى مرئي (FCP) وسرعة عرض أكبر محتوى مرئي (LCP) من خلال تضمين محتوى CSS المهم. تشتمل لغة CSS المهمة للصفحة على جميع الأنماط المستخدمة في عرضها الأولي. لمزيد من المعلومات حول الموضوع، يمكنك الاطّلاع على مقالة تأجيل صفحات CSS غير المهمة.

لاحظنا أنّ العديد من التطبيقات تُحمِّل الأنماط بشكل متزامن، ما يمنع عرض التطبيقات. يمكن حل المشكلة سريعًا من خلال تحميل الأنماط بشكل غير متزامن. بدلاً من تحميل النصوص البرمجية باستخدام media="all"، اضبط قيمة السمة media على print، وبعد اكتمال التحميل، استبدِل قيمة السمة إلى all:

<link rel="stylesheet" href="..." media="print" onload="this.media='all'">

مع ذلك، يمكن أن تؤدي هذه الممارسة إلى ظهور محتوى غير نمطي وميضًا.

يبدو أنّ الصفحة تومض أثناء تحميل الأنماط.

يعرض الفيديو أعلاه عرض صفحة تُحمِّل أنماطها بشكل غير متزامن. ويحدث الوميض لأنّ المتصفّح يبدأ أولاً في تنزيل الأنماط، ثم يعرض ترميز HTML التالي. بعد أن ينزِّل المتصفّح الأنماط، يشغّل الحدث onload لعنصر الرابط، مع تعديل السمة media إلى all، ويطبّق الأنماط على نموذج العناصر في المستند (DOM).

خلال الفترة الزمنية بين عرض HTML وتطبيق الأنماط، لا يتم تصميم الصفحة بشكل جزئي. عندما يستخدم المتصفِّح الأنماط، نلاحظ وميضًا، ما يقدّم تجربة سيئة للمستخدم وينتج عنه تراجع في متغيّرات التصميم التراكمية (CLS).

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

لنلقِ نظرة على المثال التالي:

الإجراءات غير المُوصى بها
<head>
   <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>
/* styles.css */
section button.primary {
  /* ... */
}
.list {
  /* ... */
}

مثال قبل التضمين.

في المثال أعلاه، ستقرأ المخلوقات محتوى styles.css وتحلّله، وبعد ذلك تطابق أداتَي الاختيار مع HTML وتكتشف استخدام section button.primary. وأخيرًا، ستضمّن المخلوقات الأنماط المتناظرة في <head> من الصفحة، ما ينتج عنه:

الإجراءات التي يُنصح بها
<head>
  <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
  <style>
  section button.primary {
    /* ... */
  }
  </style>
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>

مثال بعد التضمين.

بعد تضمين محتوى CSS المهم في HTML، ستجد أنّ وميض الصفحة قد اختفى:

يتم تحميل الصفحة بعد تضمين CSS.

تتوفر الآن ميزة تضمين CSS الأساسية في Angular ويتم تفعيلها تلقائيًا في الإصدار 12. إذا كنت تستخدم الإصدار 11، يمكنك تفعيله من خلال ضبط السمة inlineCritical على true في angular.json. لتفعيل هذه الميزة في Next.js، أضِف experimental: { optimizeCss: true } إلى next.config.js.

الاستنتاجات

في هذه المشاركة، تطرقنا إلى بعض أشكال التعاون بين Chrome وأُطر العمل على الويب. إذا كنت مؤلف إطار عمل وتدرك بعض المشكلات التي عالجناها في التقنية التي تستخدمها، نأمل أن تلهمك نتائجنا لإجراء تحسينات أداء مماثلة.

مزيد من المعلومات عن التحسينات يمكنك العثور على قائمة شاملة بأعمال التحسين التي أجريناها في ما يخص "مؤشرات أداء الويب الأساسية" في المشاركة التي تتضمن لمحة عن Aurora.