Codelab: טעינה מראש של נכסים קריטיים כדי לשפר את מהירות הטעינה

ב-codelab הזה, הביצועים של דף האינטרנט הבא משתפרים על ידי טעינה מראש ושליפה מראש של כמה משאבים:

צילום מסך של האפליקציה

מדידה

קודם מודדים את ביצועי האתר לפני שמוסיפים אופטימיזציות.

  • כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה ואז על מסך מלא מסך מלא.

מריצים את ביקורת הביצועים של Lighthouse ‏ (Lighthouse > Options > Performance) בגרסה הפעילה של Glitch (אפשר גם לעיין במאמר איתור הזדמנויות לשיפור הביצועים באמצעות Lighthouse).

מערכת Lighthouse מציגה את בדיקת הביקורת שנכשלה לגבי משאב שאוחזר מאוחר:

Lighthouse: ביקורת על טעינה מראש של בקשות חשובות
  • מקישים על Control+Shift+J (או על Command+Option+J ב-Mac) כדי לפתוח את כלי הפיתוח.
  • לוחצים על הכרטיסייה רשת.
חלונית הרשת עם משאב שהתגלה מאוחר

קובץ main.css לא מאוחזר על ידי אלמנט Link ‏ (<link>) שמוצב במסמך HTML, אבל קובץ JavaScript נפרד, fetch-css.js, מצרף את אלמנט Link ל-DOM אחרי אירוע window.onLoad. המשמעות היא שהקובץ מאוחזר רק אחרי שהדפדפן מסיים לנתח ולבצע את קובץ ה-JS. באופן דומה, פונט אינטרנט (K2D.woff2) שצוין בתוך main.css מאוחזר רק אחרי שקובץ ה-CSS סיים את ההורדה.

שרשרת הבקשות הקריטיות מייצגת את סדר המשאבים שהדפדפן נותן להם עדיפות ומביא אותם. בדף האינטרנט הזה, הוא נראה כרגע כך:

├─┬ / (initial HTML file)
  └── fetch-css.js
    └── main.css
      └── K2D.woff2

מכיוון שקובץ ה-CSS נמצא ברמה השלישית בשרשרת הבקשות, Lighthouse זיהה אותו כמשאב שהתגלה מאוחר.

טעינה מראש של משאבים קריטיים

הקובץ main.css הוא נכס קריטי שנדרש באופן מיידי ברגע שהדף נטען. לגבי קבצים חשובים כמו המשאב הזה, שנשלפים בשלב מאוחר באפליקציה, כדאי להשתמש בתג preload של קישור כדי להודיע לדפדפן להוריד אותו מוקדם יותר. לשם כך, מוסיפים רכיב Link לראש המסמך.

מוסיפים תג טעינה מראש לאפליקציה הזו:

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
</head>

המאפיין as משמש לזיהוי סוג המשאב שאותו מאחזרים, והמאפיין as="style" משמש לטעינה מראש של קובצי גיליונות סגנונות.

טוענים מחדש את האפליקציה ומסתכלים על החלונית Network בכלי הפיתוח.

חלונית &#39;רשת&#39; עם משאב שנטען מראש

שימו לב איך הדפדפן מאחזר את קובץ ה-CSS לפני שהניתוח של קובץ ה-JavaScript שאחראי לאחזור שלו מסתיים. בטעינה מראש, הדפדפן יודע לבצע אחזור מונע של המשאב מתוך הנחה שהוא חיוני לדף האינטרנט.

אם לא משתמשים בטכניקה הזו בצורה נכונה, היא עלולה לפגוע בביצועים כי היא יוצרת בקשות מיותרות למשאבים שלא נעשה בהם שימוש. באפליקציה הזו, details.css הוא קובץ CSS אחר שנמצא בבסיס הפרויקט, אבל הוא משמש ל/details route נפרד. כדי להראות דוגמה לשימוש שגוי בטעינה מראש, מוסיפים גם רמז לטעינה מראש של המשאב הזה.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

טוענים מחדש את האפליקציה ומסתכלים בחלונית Network (רשת). מתבצעת בקשה לאחזור של details.css למרות שהוא לא בשימוש בדף האינטרנט.

חלונית הרשת עם טעינה מראש מיותרת

‫Chrome מציג אזהרה בחלונית Console כשמשאב שנטען מראש לא נמצא בשימוש בדף תוך כמה שניות אחרי הטעינה.

אזהרה לגבי טעינה מראש במסוף

האזהרה הזו יכולה לעזור לכם לזהות אם יש לכם משאבים שנטענו מראש אבל לא נמצאים בשימוש מיידי בדף האינטרנט. עכשיו אפשר להסיר את הקישור לטעינה מראש שלא נחוץ בדף הזה.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

רשימה של כל סוגי המשאבים שאפשר לאחזר יחד עם הערכים הנכונים שצריך להשתמש בהם במאפיין as מופיעה במאמר MDN בנושא טעינה מראש.

טעינה מראש של משאבים עתידיים

Prefetch היא עוד רמז לדפדפן שאפשר להשתמש בו כדי לשלוח בקשה לנכס שמשמש לנתיב ניווט אחר, אבל בעדיפות נמוכה יותר מנכסים חשובים אחרים שנדרשים לדף הנוכחי.

באתר הזה, לחיצה על התמונה מעבירה אתכם לנתיב נפרד details/

פרטי מסלול

קובץ CSS נפרד, details.css, מכיל את כל הסגנונות שנדרשים לדף הפשוט הזה. מוסיפים רכיב קישור ל-index.html כדי לבצע אחזור מראש של המשאב הזה.

<head>
  <!-- ... -->
  <link rel="prefetch" href="details.css">
</head>

כדי להבין איך הפעולה הזו מפעילה בקשה לקובץ, פותחים את החלונית Network בכלי הפיתוח ומבטלים את הסימון של האפשרות Disable cache.

השבתת המטמון בכלי הפיתוח ל-Chrome

טוענים מחדש את האפליקציה ורואים איך מתבצעת בקשה בעדיפות נמוכה מאוד ל-details.css אחרי שכל הקבצים האחרים נמשכו.

חלונית הרשת עם משאב שנשלף מראש

כשהכלי DevTools פתוח, לוחצים על התמונה באתר כדי לעבור לדף details. מכיוון שנעשה שימוש ברכיב link ב-details.html כדי לאחזר את details.css, נשלחת בקשה למשאב כצפוי.

בקשות רשת בדף הפרטים

לוחצים על בקשת הרשת details.css בכלי הפיתוח כדי לראות את הפרטים שלה. תשימו לב שהקובץ מאוחזר ממטמון האחסון של הדפדפן.

פרטי הבקשה שאוחזרו ממטמון האחסון

באמצעות ניצול הזמן שבו הדפדפן לא פעיל, טכנולוגיית האחזור מראש שולחת בקשה מוקדמת למשאב שנדרש לדף אחר. הפעולה הזו מאיצה בקשות ניווט עתידיות, כי היא מאפשרת לדפדפן לשמור את הנכס במטמון מוקדם יותר ולהציג אותו מהמטמון כשצריך.

טעינה מראש ושליפה מראש באמצעות webpack

במאמר בנושא צמצום מטען ייעודי (payload) של JavaScript באמצעות פיצול קוד מוסבר איך להשתמש בייבוא דינמי כדי לפצל חבילה למספר מקטעים. הדוגמה הזו מראה אפליקציה פשוטה שמייבאת באופן דינמי מודול מ-Lodash כששולחים טופס.

אפליקציית Magic Sorter שמדגימה פיצול קוד

אפשר לגשת ל-Glitch של האפליקציה הזו כאן.

בלוק הקוד הבא, שנמצא ב-src/index.js,, אחראי לייבוא דינמי של השיטה כשלוחצים על הלחצן.

form.addEventListener("submit", e => {
  e.preventDefault()
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

פיצול חבילה משפר את זמני הטעינה של הדפים כי הוא מקטין את הגודל הראשוני שלה. גרסה 4.6.0 של webpack מספקת תמיכה בטעינה מראש או באחזור מראש של חלקי קוד שיובאו באופן דינמי. אם ניקח את האפליקציה הזו כדוגמה, אפשר לבצע אחזור מראש של השיטה lodash בזמן שהדפדפן לא פעיל. כשמשתמש לוחץ על הכפתור, לא חל עיכוב באחזור המשאב.

כדי לבצע אחזור מראש של נתח מסוים, משתמשים בפרמטר התגובה הספציפי webpackPrefetch בייבוא דינמי. כך זה ייראה באפליקציה הספציפית הזו.

form.addEventListener("submit", e => {
  e.preventDefault()
  import(/* webpackPrefetch: true */ 'lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

אחרי שהאפליקציה נטענת מחדש, webpack מוסיף תג prefetch למשאב בחלק head של המסמך. אפשר לראות את זה בחלונית Elements ב-DevTools.

חלונית Elements (רכיבים) עם תג prefetch (אחזור מראש)

בנוסף, כשמתבוננים בבקשות בחלונית Network, אפשר לראות שהנתח הזה מאוחזר עם עדיפות נמוכה אחרי שכל שאר המשאבים נדרשו.

חלונית הרשת עם בקשה שבוצעה מראש

למרות שהבאת נתונים מראש מתאימה יותר לתרחיש השימוש הזה, webpack תומך גם בטעינה מראש של חלקי קוד שיובאו באופן דינמי.

import(/* webpackPreload: true */ 'module')

סיכום

אחרי שתסיימו את ה-codelab הזה, תהיה לכם הבנה טובה של האופן שבו טעינה מראש או אחזור מראש של נכסים מסוימים יכולים לשפר את חוויית המשתמש באתר שלכם. חשוב לציין שאסור להשתמש בטכניקות האלה לכל משאב, ושימוש לא נכון בהן עלול לפגוע בביצועים. התוצאות הטובות ביותר מתקבלות רק כשמבצעים טעינה מראש או אחזור מראש באופן סלקטיבי.

לסיכום:

  • כדאי להשתמש ב-preload למשאבים שמתגלים בשלב מאוחר אבל הם קריטיים לדף הנוכחי.
  • כדאי להשתמש בטעינה מראש של משאבים שנדרשים לניווט עתידי או לפעולת משתמש.

לא כל הדפדפנים תומכים כרגע גם בטעינה מראש וגם באחזור מראש. כלומר, יכול להיות שלא כל המשתמשים באפליקציה יבחינו בשיפורים בביצועים.

אם אתם רוצים לקבל מידע נוסף על היבטים ספציפיים של האופן שבו טעינה מראש וטעינה מראש של משאבים יכולות להשפיע על דף האינטרנט שלכם, תוכלו לעיין במאמרים הבאים: