טעינת נכסים מראש באמצעות Preload

כיצד להשתמש ב ״rel="preload בכדי לטעון נכסים מהר יותר ולמנוע חסימת טעינה?

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

הערך preload של התכונה rel באלמנט <link> מאפשר לכם להכריז ב HTML head כי יש צורך על נכסים מסויימים להטען מוקדם ככל הניתן במהלך חייו של עמוד.

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

טעינה של נכסים בעמוד בצורה הנכונה היא אספקט חשוב ועליכם לבצעה נכון בכדי להשיג תוצאה טובה בנתון הצגת התוכן העיקרי (First Meaningful Paint).

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

אז בפוסט זה אנו נתמקד ב <link rel="preload"> – אפשרות אחת מפיטצ׳ר יחסית חדש הנקרא Resoursce Hints.

קיים גם מאמר על השימוש ב preconnect עבור Google Fonts שמתאים למצבים מסויים, אך במקרה של פונטים השימוש ב preload עליו אנו מדברים בפוסט זה הוא בדרך התשובה.

על התכונה "rel="preload בהרחבה

השימוש ב preload מתבצע בצורה הבאה:

<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">
  • את הנתיב לנכס (resource) ניתן לציין בתכונה href.
  • את סוג הנכס ניתן לציין באמצעות התכונה as.

אילו סוגי תוכן ניתן לטעון מראש באמצעות preload?

ניתן להשתמש ב preload עבור מספר סוגים או פורמטים של קבצים הכוללים בין היתר קבצי CSS, Javascript, פונטים, תמונות ועוד. הנה רשימה חלקית של סוגי הקבצים הנתמכים:

  • אודיו (audio) – קובץ אודיו בו משתמשים עם התגית <audio>.
  • מסמך (document) – מסמך HTML שנועד להיות מוטמע באמצעות <frame> או <iframe>.
  • הטמעה (embed) – נכס המוטמע באמצעות האלמנט <embed>.
  • פונט (font) – קובץ פונט.
  • תמונה (image) – קובץ תמונה.
  • סקריפט (script) – קובץ Javascript.
  • קובץ עיצוב (css) – קבצי CSS Stylesheets.

קיימים עוד סוגי תוכן שלא ציינו ברשימה זו, תנו מבט ב MDN web docs אם מעניין אתכם.

הכרזת MIME type

האלמנט <link> יכול לקבל את התכונה type בה ניתן לרשום את ה MIME type של הנכס אליו האלמנט מצביע.

הכרזת MIME type שימושית במיוחד כאשר מבצעים preloading לנכסים מפני שהיא תגרום לדפדפן לבדוק האם הוא כלל תומך בסוג הקובץ המופיע ב type ויוריד זה רק במידה והוא אכן תומך בו.

<link rel="preload" href="movie.mp4" as="video" type="video/mp4">

לא נרחיב מעבר לכך על MIME types, מוזמנים לתת מבט באותם MDN docs שהזכרנו קודם לכן.

שימוש ב media queries

כפי שאתם יודעים, ניתן להשתמש ב media queries באלמנט <link>, ומכאן שניתן לבצע preloading על בסיס ה viewport של המשתמש.

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

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

<link rel="preload" href="mobile-img.jpg" as="image" media="(max-width: 600px)">
<link rel="preload" href="desktop-img.jpg" as="image" media="(min-width: 601px)">

מספר מילים על Cross-origin

במידה ו CORS מוגדר בשרת שלכם כראוי, תוכלו לבצע preloading לנכסים ממקור אחר (דומיין אחר) כל עוד אתם מוסיפים את התכונה crossorigin לאלמנט <link>.

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

<link crossorigin rel="preload" href="fonts/assistant.woff2" as="font" type="font/woff2">

מתי עלינו להשתמש ב preload?

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

חשוב להבין כי הדפדפן לא מבצע שום פעולה עם אותו נכס לאחר שהוריד אותו. הוא אינו מריץ סקריפטים והוא לא מיישם CSS. הדבר היחיד ש <link rel="preload"> מבצע הוא לשמור את הנכס בזכרון, כך שברגע שמישהו דורש אותו – הוא יהיה זמין מיידית. בוא ניתן שתי דוגמאות פשוטות:

דוגמה א׳

למשל, במקרה בו אתם טוענים פונט רשת כלשהו ע״י font-face@ וה CSS של פונט זה נמצא בקובץ חיצוני. אז לצורך הדוגמה נניח וזה קובץ ה HTML שלנו:

<link rel="stylesheet" href="index.css" />

ונניח שזה קובץ ה CSS:

@font-face {
    src: url('assistant.woff2') format('woff2');
}

כברירת מחדל, assistant.woff2 יתחיל לרדת רק בנקודה בה index.css ייטען ויתממש. במקום להמתין לנקודה זו ניתן באמצעות preload ליזום את הבקשה מוקדם יותר, ומכיוון והוא יהיה נגיש מהר יותר לטובת רינדור העמוד – הגולשים יסבלו פחות מתופעת ה FOUT עלינו דיברנו בפוסט המדבר על התכונה font-display.

זה המקום לומר שרצוי ואפילו מומלץ להשתמש ב preload וגם יחד עם התכונה font-display בכדי לבצע אופטימיזציה לטעינת פונטים.

דוגמה ב׳

דוגמה נוספת היא מצב בו אתם מחלקים את קבצי העיצוב שלכם לטובת הצגה מהירה יותר של החלק העליון הקריטי של העמוד (Critical Path). קובץ אחד לחלקו הקריטי של העמוד וקובץ שני לשאר העמוד:

<style>
  /* Inlined critical styles */
</style>

<link rel="preload" href="/non-critical.css" as="style" />

<script>
  /* Non-critical styles */
  loadCSS('/non-critical.css');
</script>

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

אז מהם בעצם נכסים החוסמים טעינה?

לפני שנמשיך, בואו נסביר מה הכוונה בנכסים שחוסמים טעינה (Render-Blocking Resources).

כאשר בקשה לנכס מסויים חוסמת טעינה, זה אומר בגדול כי שה event בשם window.onload לא יופעל (triggered) עד שהבקשה תסתיים והנכס יירד במלואו.

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

תנו מבט בקוד הבא:

<html>
  <head>
    <link
      rel="stylesheet"
      href='https://fonts.googleapis.com/css?family=Roboto:400,600|Material+Icons'>

    <style>
      html {
        font-family: Roboto;
      }
    </style>
  </head>
  <body>
    Hello

    <script>
      window.onload = function () {
        console.log('Loaded');
      }
    </script>
  </body>
</html>

אם אטען קובץ HTML זה בדפדפן ואתן מבט בלשונית Network ב Chrome Dev Tools, אראה כי הטקסט Loaded נרשם בקונסול בדיוק לאחר שקובץ ה CSS נטען כפי שהתמונה הבאה ממחישה:

Render Blocking CSS - דוגמה א׳

בכדי להבחין בתוצאה שיניתי את מהירות החיבור (throttling) ל Slow 3G.

בואו נשנה את תגית ה link בכדי ליזום את הבקשה מוקדם יותר:

<link
  rel="preload"
  as="style"
  href='https://fonts.googleapis.com/css?family=Roboto:100,900|Material+Icons'>

כעת, אם ננקה את הקאש ונרענן את העמוד, נגלה (עם הרבה מאד תשומת לב) כי הטקסט Loaded מוצג בדיוק לפני שהבקשה ל CSS החלה כפי שהתמונה הבאה ממחישה:

Render Blocking CSS - דוגמה ב׳

רגע, שמתם לב במקרה שקפצה לה הערה כתומה בקונסול? ההערה באה להזהיר אותנו כי ביצענו preloading לנכס אך לא השתמשנו בו בפועל.

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

מממ… אז כיצד מיישמים את ה CSS?

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

<link
  rel="preload"
  as="style"
  onload="this.rel = 'stylesheet'"
  href='https://fonts.googleapis.com/css?family=Roboto:100,900|Material+Icons'>

על ידי קביעת התכונה rel ל stylesheet אנו מציינים לדפדפן כי עליו להשתמש בנכס זה. מכיוון וזה כבר שמור כבר בזכרון מפאת השימוש ב preload הוא אינו מוריד נכס זה שוב ומיישם אותו מיידית.

מאחר ופתרון זה מסתמך על Javascript, נכון יהיה להוסיף את התגית <noscript> כעתודה לסיטואציה בה Javascript מבוטל בדפדפן:

<link
  rel="preload"
  as="style"
  onload="this.rel = 'stylesheet'"
  href='https://fonts.googleapis.com/css?family=Roboto:100,900|Material+Icons'>

<noscript>
  <link
    rel="stylesheet"
    href='https://fonts.googleapis.com/css?family=Roboto:100,900|Material+Icons'>
</noscript>

זוהי הגישה המודרנית והנכונה לטעינת CSS ויישומו מיידית באמצעות preload.

ומה לגבי טעינה מראש של Javascript

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

הדוגמה הבאה נלקחה ממאמר בגוגל ומראה שיישום Javascript שנטען מראש מתבצע בצורה קצת שונה. עליכם לקבוע את התכונה src של הקובץ ולהוסיפו ל DOM:

<link rel="preload" href="used-later.js" as="script">
<!-- ... -->
<script>
  var usedLaterScript = document.createElement('script');
  usedLaterScript.src = 'used-later.js';
  document.body.appendChild(usedLaterScript)
</script>

לסיכום

טעינה מראש של נכסים מספקת לכם יותר שליטה על כיצד נכסים נטענים ומשפרת (פוטנציאלית) את מהירות האתר. בסאבי בלוג אם מעניין אתכם – אני טוען את הפונטים מראש באמצעות preload.

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

מעבר לכך אל תתבלבלו בין preload ל prefetch. אין להשתמש ב preload אם אינכם צריכם את הנכס מיידית לאחר שהעמוד נטען. אם אתם צריכים זה מאוחר יותר, נאמר בעמוד הבא, או אם הנכס אינו בעל חשיבות גבוהה להצגת העמוד (נאמר הסקריפט של analytics) – עליכם להשתמש ב prefetch או reource hint אחר…

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

רועי יוסף
רועי יוסף

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

0תגובות...

השאירו תגובה

Up!