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

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

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

تضمين الخطوط

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

<!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.