Search

טעינת נכסים מראש באמצעות 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 או resource hint אחר…

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

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

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

19 תגובות...
  • אמנון 11 יוני 2020, 10:33

    שלום רב,
    בתוצאת הבדיקה של גוגל פייג Page Speed הודעה שאני צריך לעשות link rel=preload לכתובת הבאה:
    https://bshcpa.co.il/wp-content/themes/oceanwp/assets/fonts/simple-line-icons/Simple-Line-Icons.woff2?v=2.4.0.
    לא ברור איזה קוד נדרש ובאיזה קובץ בתבנית אני אמור לשתול אותו. אשמח להכוונה.
    תודה

    • רועי יוסף 11 יוני 2020, 13:29

      היי אמנון,

      הוסף את הקוד הבא לקובץ functions.php של התבנית שלך:

      function savvy_preload_fonts() {
          echo '<link rel="preload" as="font" crossorigin href="' . get_template_directory_uri() .'/assets/fonts/simple-line-icons/Simple-Line-Icons.woff2" type="font/woff2">' ."\n";
      
      }
      add_action( 'wp_head', 'savvy_preload_fonts', 0 );
      • אלי 20 דצמבר 2020, 14:16
        A preload  was found for "https://ametalocksmith.ca/wp-content/cache/min/1/1f0791d30d8c11731122859d9197b7d7.js" but was not used by the browser. Check that you are using the `crossorigin` attribute properly.

        מה אני אמור להטמיע והיכן? בעיה אחרת Preload key requests מה מטמיעים והיכן?

  • אמנון 11 יוני 2020, 13:43

    תודה רועי,
    הוספתי את הקוד לתבנית וניקיתי קאש ואין שינוי עדיין מקבל את ההודעה שנדרש rel=preload.
    כעת גם התווספה אזהרה:
    אזהרות: מערכת Lighthouse לא הצליחה לבדוק באופן אוטומטי את ערך תצוגת הגופן של כתובת ה-URL הבאה: https://bshcpa.co.il/wp-content/themes/oceanwp/assets/fonts/simple-line-icons/Simple-Line-Icons.woff2.

    • רועי יוסף 11 יוני 2020, 13:51

      כנס לקובץ https://bshcpa.co.il/wp-content/themes/oceanwp/assets/css/third/simple-line-icons.min.css והחלף את השורות הבאות:

      @font-face {
          font-family: 'simple-line-icons';
          src: url('../../fonts/simple-line-icons/Simple-Line-Icons.eot?v=2.4.0');
          src: url('../../fonts/simple-line-icons/Simple-Line-Icons.eot?v=2.4.0#iefix') format('embedded-opentype'), url('../../fonts/simple-line-icons/Simple-Line-Icons.woff2?v=2.4.0') format('woff2'), url('../../fonts/simple-line-icons/Simple-Line-Icons.ttf?v=2.4.0') format('truetype'), url('../../fonts/simple-line-icons/Simple-Line-Icons.woff?v=2.4.0') format('woff'), url('../../fonts/simple-line-icons/Simple-Line-Icons.svg?v=2.4.0#simple-line-icons') format('svg');
          font-weight: normal;
          font-style: normal;
      }

      באלו:

      @font-face {
          font-family: 'simple-line-icons';
          src: url('../../fonts/simple-line-icons/Simple-Line-Icons.eot?v=2.4.0');
          src: url('../../fonts/simple-line-icons/Simple-Line-Icons.eot?v=2.4.0#iefix') format('embedded-opentype'), url('../../fonts/simple-line-icons/Simple-Line-Icons.woff2?v=2.4.0') format('woff2'), url('../../fonts/simple-line-icons/Simple-Line-Icons.ttf?v=2.4.0') format('truetype'), url('../../fonts/simple-line-icons/Simple-Line-Icons.woff?v=2.4.0') format('woff'), url('../../fonts/simple-line-icons/Simple-Line-Icons.svg?v=2.4.0#simple-line-icons') format('svg');
          font-weight: normal;
          font-style: normal;
          font-display: swap;
      }
      • אמנון 11 יוני 2020, 14:04

        היי,
        איך אני מגיע לקובץ ששלחת בקישור לצורך העריכה שלו? האם השורות נמצאות גם בקובץ functions.php? אם כן, אני לא מוצא את השורות..

        • רועי יוסף 11 יוני 2020, 14:25

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

          • אמנון 11 יוני 2020, 21:15

            היי,
            בוצע! נכנסתי לספרייה והוספתי לקובץ רק את השורה font-display: swap (כי זו השורה שמבדילה בין המצב לפני לאחרי). התוצאה היא שזה צמצם את הזמן, אבל עדיין נותרה ההערה לאחר בדיקת המהירות ב- PS שיש לטעון מראש.

            1. השאלה – האם בעקבות הפעולות שהמלצת, ההערה אמורה להיעלם לגמרי או רק לצמצם את זמן הטעינה?
            2. האם נדרש לבצע את שתי הפעולות שהמלצת במקביל: גם את הקוד בקובץ functions.php ובנוסף את השינוי בקובץ שעתה השלמתי.

            • אמנון 11 יוני 2020, 21:19

              ביצעתי את השינויים על דומיין משוכפל למקרה ותרצה לבדוק
              https://stage.bshcpa.co.il/

            • רועי יוסף 11 יוני 2020, 21:20

              כן, עלייך לבצע את שתי הפעולות. איני יכול לעזור לך מעבר לכך לצערי…. בהצלחה!

  • אמנון 11 יוני 2020, 21:21

    עזרת מעל ומעבר. תודה רבה!

  • שרה טיקטינסקי קליינר 16 יוני 2020, 10:21

    wow רועי, קראתי את ההתכתבות כאן. אתה ממש נדיב. לדעתי, זה דווקא משרת אותך. לפחות, בעיניי.

  • שי גודלנברג 19 ינואר 2021, 13:42

    מאמר מעולה וכל הכבוד על העזרה לאחרים פה 🙂

  • רוב 2 פברואר 2021, 9:46

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

    • רועי יוסף 2 פברואר 2021, 10:30

      lightspeed לא מאפשר preload של פונטים, יש לעשות זאת ידנית…

      • רוב 2 פברואר 2021, 11:17

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

        • רועי יוסף 2 פברואר 2021, 11:22

          כן, כן ולא…

          • רוב 2 פברואר 2021, 14:03

            תודה, איך מחליפים את מה שקיים עכשיו?

תגובה חדשה

ניווט מהיר

Up!
לבלוג