אופטימיזציה של תמונות באמצעות ההנחיה בנושא תמונות זוויתיות

Kara Erickson
Kara Erickson
Leena Sohoni
Leena Sohoni

במאי 2022, צוותי Aurora ו-Agular הודיעו שהם ישתפו פעולה כדי ליצור הוראת תמונות עבור Angular. ההוראה שוחררה לאחרונה לתצוגה מקדימה למפתחים כחלק מ-Agular v14.2. הפוסט הזה מתאר איך ההוראה החדשה לתמונות (NgOptimizedImage) תומכת באופטימיזציה של תמונות ב-Agular.

רקע

תמונות הן רכיב נפוץ וקריטי בחוויית המשתמש באינטרנט, וב-99.9% מדפי האינטרנט נוצרות בקשות לתמונה אחת או יותר. תמונות הן גם הגורם המשמעותי ביותר למשקל הדף, והן מייצגות חציון של 982KB לכל דף.

בגלל שמספרם וגודלם הולך וגדל, תמונות יכולות לפגוע בביצועים של דפי אינטרנט ולהשפיע על מדדי מדדי הליבה לבדיקת חוויית המשתמש באתר. ב-79.4% מהדפים למחשבים, בשנת 2021, תמונה הייתה הרכיב Largest Contentful Paint (LCP). השימוש בתמונות שעברו אופטימיזציה הפך למאמץ קבוע עבור רבים מאיתנו.

אנשי צוות Aurora מאמינים במינוף העוצמה של frameworks כדי לספק פתרונות מובנים לאתגרים נפוצים של מפתחים. הכניסה הראשונה שלהם למרחב האופטימיזציה של תמונות הייתה רכיב התמונה Next.js. הם חשבו שהרכיב הזה משמש כבסיס לבדיקה אם שיפור חוויית הפיתוח (DX) של אופטימיזציית התמונות עשוי להוביל לשיפורים בביצועים של אפליקציות נוספות שעושות שימוש ב-frameworks.

קבוצת התוצאות הראשונה ממשתמש Next.js, Leboncoin, מעודדת. לבונקוין הייתה שיפור משמעותי ב-LCP (מ-2.4 שניות ל-1.7 שניות) אחרי שהתחילו להשתמש ב-next/image. לאחר מכן, האימוץ של next/image בקהילה השפיעה על הגדלת המקורות של Next.js שעמדו בספי ה-LCP. בקרוב התקבלו בקשות לתכונות דומות ב-frameworks אחרות, שאחת מהן הייתה Angular.

בעקבות זאת, Aurora התייעץ עם Angular ו-Nuxt כדי ליצור אב טיפוס של רכיבי תמונה עבור ה-frameworks האלה. רכיב התמונה של Nuxt פורסם בשנה שעברה. עכשיו שוחררה ההוראה Angular image (NgOptimizedImage) כדי להגדיר את ברירת המחדל של האופטימיזציה של התמונות ב-Agular.

Opportunity

Angular היא אחת ממסגרות ה-JavaScript המובילות שבהן מפתחים משתמשים כיום. הוא משמש יותר מ-50,000 מקורות שנסרקים על ידי HTTPArchive בנייד, ומתגאה בערך 3 מיליון הורדות שבועיות ב-NPM.

LCP עבור אתרי Angular במהלך השנה האחרונה.

כשבוחנים את הציונים במדדי הליבה לבדיקת חוויית המשתמש באתר, עדיין נדרשת עבודה באחוז המקורות של Angular שעומדים בערכי LCP 'טובים'. רק ב-18.74% מהאתרים ב-Angular היה LCP טוב בנייד ביוני 2022. מכיוון שתמונות הן אלמנט ה-LCP ביותר מ-70% מדפי האינטרנט בניידים ובמחשבים, תמונות LCP לא אופטימליות הן אחד מהגורמים העיקריים לירידה בשיעור ה-LCP באתרים של Angular.

ההוראה Angular image נועדה לעזור לשפר את הנתונים האלה.

MVP להוראה NgOptimizedImage

ה-MVP של הוראת האימג' של Angular מסתמך על לקחים מרכיבי התמונה ש-Aurora יצרה עד עכשיו, תוך התאמת העיצוב לחוויית הרינדור בצד הלקוח של Angular. רבות מהבעיות הרגילות של אופטימיזציה של תמונות טופלו באמצעות:

  • ברירות מחדל מוצקות.
  • הטלת שגיאות או אזהרות כדי להבטיח תאימות לשיטות מומלצות.

הפרטים העיקריים של העיצוב:

  1. טעינה מדורגת חכמה

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

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

  2. תעדוף של תמונות חשובות

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

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

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

    במצב פיתוח, ההוראה משתמשת גם ב-PerformanceObserver API כדי לוודא שתמונת ה-LCP סומנה כ-priority כמצופה. אם הוא לא מסומן בתור priority, תושמע שגיאה שתנחה את המפתח להוסיף את המאפיין priority לתמונת ה-LCP.

    בסופו של דבר, השילוב הזה של אוטומציה ותאימות מבטיח שלתמונת ה-LCP יהיה רמז לpreconnect, ערך מאפיין fetchpriority של high, ולא ייטען באופן מדורג.

  3. הגדרה אופטימלית של כלי תמונות פופולריים

    מומלץ שאפליקציות של Angular תשתמשו ברשתות CDN של תמונות, שמספקות בדרך כלל שירותי אופטימיזציה כברירת מחדל.

    ההוראה מעודדת שימוש ברשתות CDN של תמונות, כי היא מספקת חוויית מפתח מעניינת במיוחד (DX) כדי להגדיר אותם באפליקציה. היא תומכת ב-API של טעינה שמאפשרת להגדיר את ספק ה-CDN ואת כתובת ה-URL הבסיסית בהגדרה שלך. לאחר ההגדרה, צריך להגדיר רק את שם הנכס בתגי העיצוב. לדוגמה,

    // in module providers:
    provideImgixLoader('https://mysite.net/assets/')
    
    // in markup
    <img ngSrc="image.png" >
    <img ngSrc="image2.png" >
    

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

    <img src="https://mysite.net/assets/image.png">
    <img src="https://mysite.net/assets/image2.png">
    

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

  4. שגיאות ואזהרות מובנות

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

    1. תמונות לא בגודל: הוראת התמונה גורמת לשגיאה אם תגי העיצוב של התמונות לא הגדירו רוחב וגובה מפורשים. תמונות לא גדולות עלולות לגרום לשינויים בפריסה, להשפיע על המדד Cumulative Layout Shift (CLS) של הדף. כדי למנוע מצב כזה, מומלץ לציין בתמונות את המאפיינים width ו-height.

    2. יחס גובה-רוחב: בהוראת התמונה מוצגת שגיאה כדי ליידע את המפתחים אם יחס הגובה-רוחב של width:height שהוגדר ב-HTML לא קרוב ליחס הגובה-רוחב של התמונה המעובדת בפועל. לכן, התמונה עלולה להיראות מעוותת במסך. הדבר יכול להתרחש אם

      1. הגדרתם מידות שגויות (רוחב או גובה) בטעות, או
      2. אם הגדרתם מאפיין אחד באחוזים ב-CSS, אבל לא את המימד השני (לדוגמה, width: 100% צריך height: auto כדי להבטיח שהתמונה תגדל בשני המימדים).
    3. תמונות גדולות יותר: אם בתמונה לא מוגדרת srcset והתמונה המהותית גדולה באופן משמעותי מהתמונה המעובדת, בהנחיה תוצג אזהרה שמרמזת על שימוש במאפיינים srcset ו-sizes.

    4. דחיסות התמונה: אם תנסו לכלול תמונה ב-srcset בדחיסות פיקסלים של יותר מ-3x, תוצג הודעת שגיאה. בדרך כלל לא מומלץ להשתמש בתיאורים שגבוהים מ-2x, כי יש לכך תוצאה לא מכוונת של אילוץ ההורדה של תמונות ענקיות במכשירים ניידים ברזולוציה גבוהה. בנוסף, העין האנושית לא יכולה לזהות הבדל גדול בהרבה מפי 2.

אתגרים

התאמת האסטרטגיות לאופטימיזציה של תמונות כך שיפעלו במסגרת בצד הלקוח היה האתגר העיקרי במהלך הפיתוח של NgOptimizedImage. חוויית הרינדור שמוגדרת כברירת מחדל ב-Next.js היא 'רינדור בצד השרת' (SSR) או 'יצירת אתרים סטטיים (SSG)', ואילו ב-Angular הוא רינדור בצד הלקוח (CSR). למרות ש-Agular תומך בספריית SSR – angular/universal – רוב האפליקציות ב-Agular (כ-60%) משתמשות ב-CSR.

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

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

  1. טיפים לתמיכה במשאבים

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

    הוספה ידנית: למפתחים קשה להוסיף באופן ידני את הרמז למשאב preload. ב-Angular משתמשים בקובץ index.html משותף אחד לכל הפרויקט או לכל המסלולים באתר. לכן, הערך <head> של המסמך זהה בכל מסלול (לפחות בזמן ההצגה). הוספת רמז preload ל-<head> תגרום לכך שהמשאב ייטען מראש לכל המסלולים, גם אם הוא לא נדרש. לכן, לא מומלץ להוסיף רמזים של preload באופן ידני.

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

    בגרסה הראשונה של ההוראה, שילוב של הרמזים של preconnect ורמזים של fetchpriority משמש כדי לתעדף את התמונה, במקום preload. עם זאת, אורורה עובדת כרגע עם הצוות של Angular CLI כדי לאפשר החדרה אוטומטית של רמזים למשאבים בזמן ה-build – כדאי להמשיך להתעדכן!

  2. אופטימיזציה של הגודל והפורמט של התמונות בשרת

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

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

השפעה

ההדגמה הבאה ממחישה את ההבדל שהוראת התמונה Angular יכולה לעשות לביצועי התמונות. היא משווה בין שני אתרים:

Website One: משתמשים ברכיבי <img> מקוריים עם תמונות שמוצגות דרך Imgix CDN (עם אפשרויות הגדרה כברירת מחדל).

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

השוואה ברצועת תמונות: אתר ראשון עם תגי תמונה מקורית לעומת אתר שני עם הוראת תמונה של Angular.

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

אחד מהשותפים האלה היה Land's End. הם היו מצפים שהאתר שלהם יהיה מקרה בדיקה טוב לתוצאות שאפליקציות אמיתיות יוכלו לראות.

בדיקות מעבדה של Lighthouse בוצעו בסביבת QA לפני ואחרי השימוש בהוראת האימג'. במחשב, ערך ה-LCP החציוני ירד מ-12.0 שניות ל-3.0 שניות – שיפור של 75% ב-LCP. בנייד, ערך ה-LCP החציוני ירד מ-20.2 שניות ל-12.0 שניות (שיפור של 40.6%).

מפת דרכים עתידית

זהו רק החלק הראשון של העיצוב של ההוראה Angular Image. בגרסאות הבאות מתוכננות תכונות רבות נוספות, כולל:

  • תמיכה טובה יותר בתמונות רספונסיביות:

    נכון לעכשיו, ב-NgOptimizedImage יש תמיכה בשימוש ב-srcset, אבל צריך לספק את המאפיינים srcset ו-sizes באופן ידני לכל תמונה. בעתיד, ההוראה תוכל ליצור את המאפיינים srcset ו-sizes באופן אוטומטי.

  • החדרה אוטומטית של רמזים למשאבים

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

  • תמיכה ב-Agular SSR

    גרסת ה-MVP עוצבה תוך התחשבות במגבלות של נציג שירות לקוחות של Angular, אבל חשוב גם לבדוק פתרונות לאופטימיזציה של תמונות עבור Angular SSR (זוויתי/אוניברסלי).

  • שיפורים בחוויית הפיתוח

    לפי הדרישות של NgOptimizedImage, צריך לציין את המאפיינים width ו-height לכל תמונה. עם זאת, ציון הערכים האלה לכל תמונה עשוי לעייף עבור חלק מהמפתחים. יש פוטנציאל לשפר את חוויית המפתח באיטרציה הבאה באופן הבא:

    1. לתמוך במצב נוסף (דומה לאפשרות פריסת התמונה "fill" ב-Next.js) שלא מחייב הגדרה של רוחב/גובה מפורש.
    2. שימוש בשילוב עם CLI כדי להגדיר אוטומטית את הרוחב והגובה של תמונות מקומיות על ידי קביעת המידות של התמונה בפועל.

סיכום

ההוראה בנושא תמונות ב-Agular תהיה זמינה למפתחים בשלבים, החל מגרסת התצוגה המקדימה למפתחים בגרסה 14.2.0. רוצה לנסות את NgOptimizedImage ולשלוח משוב?

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