ביצוע קל ופשוט של ביצועי האינטרנט - מהדורת 2018 של Google I/O

בכנס Google IO 2018 הצגנו סיכום של כלים, ספריות ושיטות אופטימיזציה שיעזרו לכם לשפר את ביצועי האתרים בקלות. כאן נסביר עליהם באמצעות האפליקציה Oodles Theater. אנחנו גם מדברים על הניסויים שלנו בטעינה חזותית ועל היוזמה החדשה Guess.js.

Addy Osmani
Addy Osmani
Ewa Gasperowicz

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

הצורך בביצועים

האינטרנט הולך ונעשה כבד יותר מדי שנה. אם נבדוק את מצב האינטרנט נראה שדף חציוני בנייד עומד במשקל של כ-1.5MB, כשרובו הוא JavaScript ותמונות.

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

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

פירמידה של היררכיית UX
איור 1. עד כמה המהירות חשובה למשתמשים? (Speed Matters, Vol. 3)

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

Lighthouse – בסיס לתהליך העבודה לשיפור הביצועים

Lighthouse הוא חלק מכלי הפיתוח ל-Chrome שמאפשר לבצע ביקורת של האתר, ומספק טיפים לשיפור.

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

ביקורות חדשות של Lighthouse
איור 2. ביקורות חדשות של Lighthouse

כדי להבין איך אפשר להפיק מהם תועלת, נשתמש בדוגמה מעשית: אפליקציית Oodles Theater. זוהי אפליקציית אינטרנט קטנה לדגמה, שבה אפשר לנסות כמה מה-Google Doodles האינטראקטיביים האהובים עלינו ואפילו לשחק במשחק או שניים.

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

דוח Lighthouse על אפליקציית Oodles
איור 3. דוח Lighthouse על אפליקציית Oodles

הביצועים הראשוניים של האפליקציה שלנו, כפי שאפשר לראות בדוח Lighthouse, היו די גרועים. ברשת של 3G, המשתמשים היו צריכים להמתין 15 שניות עד לציור המשמעותי הראשון, או עד שהאפליקציה תהיה אינטראקטיבית. ב-Lighthouse הוצגו המון בעיות באתר שלנו, ודירוג הביצועים הכולל של 23 משקף בדיוק את זה.

הדף היה במשקל של כ-3.4MB – היינו צריכים להוציא ממנו קצת שומן.

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

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

הסרת משאבים מיותרים

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

היתרונות של הקטנה
איור 4. דחיסת קובצי JavaScript ו-CSS והקטנת נפחם

ב-Lighthouse מודגשת ההזדמנות הזו בבדיקה של CSS ו-JavaScript ללא דחיסה. השתמשנו ב-webpack בתהליך ה-build שלנו, לכן כדי להקטין את התצוגה פשוט השתמשנו בפלאגין של Uglify JS.

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

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

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

gzip היא דרך פופולרית מאוד לדחיסת נתונים, אבל גם מנגנונים אחרים כמו Zopfli ו-Brotli צוברים תאוצה. רוב הדפדפנים תומכים ב-Brotli, ואפשר להשתמש בקובץ בינארי כדי לדחוס מראש את הנכסים לפני ששולחים אותם לשרת.

שימוש במדיניות מטמון יעילה

השלב הבא היה להבטיח שלא נשלח משאבים פעמיים אם אין צורך.

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

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

הסרת קוד שלא בשימוש

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

בדיקת כיסוי הקוד בכלי הפיתוח
איור 5. בדיקת הכיסוי של הקוד

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

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

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

הבעיה הזו זוהתה גם על ידי Lighthouse בבדיקת כללי ה-CSS שאינם בשימוש. הבדיקה הראתה חיסכון פוטנציאלי של יותר מ-400KB. אז חזרנו לקוד שלנו והסרנו את החלק של JavaScript וגם את החלק של CSS בספרייה הזו.

אם משחררים את מתאם MVC, הסגנונות שלנו יורדים ל-10KB
איור 6. אם משחררים את מתאם MVC, הסגנונות שלנו יורדים ל-10KB!

בעקבות זאת, הגודל של חבילת ה-CSS שלנו ירד פי 20, וזה די טוב עבור התחייבות קטנה באורך שורה אחת.

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

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

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

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

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

הימנעות מטען שימושי עצום ברשת

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

מערכת Lighthouse הצליחה לזהות בעיה בחלק מהמטענים הייעודיים (payload) ברשת שלנו באמצעות ביקורת Enormous network payload.

זיהוי מטענים ייעודיים (payloads) עצומים ברשת
איור 8. זיהוי עומסי נתונים עצומים ברשת

כאן ראינו שיש לנו קוד בנפח של יותר מ-3MB שנשלח להורדה – וזה הרבה מאוד, במיוחד בנייד.

בראש הרשימה הזו, Lighthouse הדגיש שיש לנו חבילת ספקי JavaScript בנפח 2MB של קוד לא דחוס. זו גם בעיה ש-webpack מדגיש.

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

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

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

ביקורת חבילת JavaScript
איור 9. ביקורת של חבילות JavaScript

התחלנו עם כלי הניתוח של חבילות Webpack, שדיווח לנו שאנחנו כוללים תלות בשם unicode, שהיא 1.6MB של JavaScript לאחר ניתוח, כך הרבה יותר.

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

לאחר מכן עברנו לכלי אחר, BundlePhobia. זהו כלי שמאפשר להזין את השם של כל חבילה ב-NPM ולראות בפועל מהו הגודל המשוער שלה אחרי דחיסה מינימלית ודחיסה ב-Gzip. מצאנו חלופה נהדרת למודול ה-slug שבו השתמשנו, שמשקלו רק 2.2KB, ולכן החלפנו אותו.

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

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

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

קיצור זמן האתחול של JavaScript באמצעות פיצול קוד

למרות שלמשא המועמס (payload) גדול ברשת יכולה להיות השפעה גדולה על האפליקציה שלנו, יש עוד דבר שיכול להשפיע מאוד, וזה JavaScript.

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

כך דפדפן מעבד JavaScript.

עיבוד JavaScript
איור 10. עיבוד JavaScript

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

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

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

זמן האתחול של JavaScript
איור 11. בדיקת זמן האתחול של JavaScript

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

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

פיצול קוד הוא כמו פיצה

בשיטה של פיצול קוד, במקום לתת למשתמשים את מלוא הערך של ה-JavaScript של פיצה, מה יקרה אם תשלחו להם רק פרוסה אחת בכל פעם, לפי הצורך?

אפשר להחיל את פיצול הקוד ברמת המסלול או ברמת הרכיב. הוא עובד מצוין עם React ו-React Loadable,‏ Vue.js,‏ Angular,‏ Polymer,‏ Preact וספריות רבות אחרות.

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

פיצול קוד באמצעות ייבוא דינמי
איור 13. פיצול קוד באמצעות ייבוא דינמי

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

באופן כללי, אם אתם מפתחים חוויית שימוש חזקה ב-JavaScript, הקפידו לשלוח את הקוד רק למשתמשים הרלוונטיים.

אם אתם משתמשים ב-webpack, כדאי להיעזר במושגים כמו חלוקת קוד, לבדוק רעיונות כמו tree shaking ולעיין במאגר webpack-libs-optimizations כדי לקבל כמה רעיונות לקיצור גודל הספרייה.

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

בדיחה על ביצועי טעינת תמונות

באפליקציית Oodle אנחנו משתמשים בהרבה תמונות. לצערנו, ב-Lighthouse לא התלהבו ממנו כמונו. למעשה, נכשלנו בכל שלושת הבדיקות שקשורות לתמונות.

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

בדיקות של תמונות
איור 14. בדיקות תמונות ב-Lighthouse

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

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

גישה אוטומטית יותר היא להוסיף שלב של אופטימיזציה של תמונות לתהליך ה-build, באמצעות ספריות כמו imagemin.

כך תוכלו לוודא שהתמונות שיתווספו בעתיד יותאמו אוטומטית. שירותי CDN מסוימים, כמו Akamai או פתרונות של צד שלישי כמו Cloudinary,‏ Fastly או Uploadcare, מציעים פתרונות מקיפים לאופטימיזציה של תמונות. כך תוכלו גם לארח את התמונות שלכם בשירותים האלה.

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

לפני ואחרי האופטימיזציה
איור 15. לפני ואחרי אופטימיזציה

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

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

שימוש בפורמט הנכון לתוכן מונפש

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

באפליקציית Oodle, השתמשנו ב-GIF כסצנת פתיחה בדף הבית. לפי Lighthouse, אפשר לחסוך יותר מ-7MB על ידי מעבר לפורמט וידאו יעיל יותר. הקליפ שלנו משקלל כ-7.3MB, יותר מדי בשביל כל אתר סביר, ולכן הפכנו אותו לאלמנט וידאו עם שני קובצי מקור – mp4 ו-WebM כדי לספק תמיכה רחבה יותר בדפדפנים.

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

השתמשנו בכלי FFmpeg כדי להמיר את קובץ ה-GIF האנימציה לקובץ MP4. פורמט WebM מציע חיסכון גדול עוד יותר - ממשק ה-API של ImageOptim יכול לבצע המרה כזו עבורך.

ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4

הצלחנו לחסוך יותר מ-80% ממשקל האריזה הכולל בזכות ההמרה הזו. כך הצלחנו להקטין את הגודל ל-1MB בערך.

עדיין, 1MB הוא משאב גדול להעברת החוט כלפי מטה, במיוחד למשתמשים שרוחב הפס שלהם מוגבל. למזלנו, הצלחנו להשתמש ב-Effective Type API כדי להבין שהם משתמשים ברוחב פס איטי, ובמקום זאת שלחנו להם קובץ JPEG קטן בהרבה.

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

if (navigator.connection.effectiveType) { ... }

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

טעינה מדורגת של תמונות מחוץ למסך

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

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

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

<!-- Import library -->
import lazysizes from 'lazysizes'  <!-- or -->
<script src="lazysizes.min.js"></script>

<!-- Use it -->

<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w"/>

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

אחרי השינוי הזה, אחזור התמונות שלנו מתבצע על פי דרישה. אם אתם רוצים להעמיק בנושא, כדאי לעיין בimages.guide – מקור מידע שימושי ומקיף מאוד.

איך לעזור לדפדפן לספק משאבים קריטיים מוקדם

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

אפשרות שימושית היא שאנחנו, ככותבים של הדף, נודיע לדפדפן מה באמת חשוב לנו. למרבה המזל, בשנים האחרונות ספקי הדפדפנים הוסיפו כמה תכונות שיעזרו לנו בכך, למשל רמזים לגבי משאבים כמו link rel=preconnect,‏ preload או prefetch.

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

נראה איך Lighthouse מנחה אותנו להשתמש ביעילות בחלק מהתכונות האלה.

הדבר הראשון שאומרים לנו ב-Lighthouse הוא להימנע מריבוי נסיעות הלוך ושוב יקרות לכל מקור שהוא.

הימנעות מכמה נסיעות הלוך ושוב יקרות לכל מקור
איור 17. הימנעות מכמה נסיעות הלוך ושוב יקרות לכל מקור

באפליקציית Oodle אנחנו משתמשים הרבה ב-Google Fonts. בכל פעם שמשחררים גיליון סגנונות של Google Font בדף, הוא מחבר עד שני תת-דומיינים. מה ש-Lighthouse אומר לנו הוא שאם נוכל לחמם את החיבור הזה, נוכל לחסוך עד 300 אלפיות השנייה בזמן החיבור הראשוני.

בעזרת הקישור rel preconnect, אנחנו יכולים להסוות ביעילות את זמן האחזור הזה.

במיוחד במוצרים כמו Google Fonts, שבהם קובצי ה-CSS של גווני הגופן מתארחים ב-googleapis.com ומשאבי הגופן מתארחים ב-Gstatic, ההשפעה יכולה להיות משמעותית מאוד. החלנו את האופטימיזציה הזו וקיצנו כמה מאות אלפיות שנייה.

ההצעה הבאה של Lighthouse היא לטעון מראש בקשות למפתחות.

טעינה מראש של בקשות עיקריות
איור 18. טעינה מראש של בקשות למפתחות

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

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

טעינת גופן אינטרנט מראש נראית כך: מציינים את rel=preload, מעבירים את as עם סוג הגופן ואז מציינים את סוג הגופן שרוצים לטעון, למשל woff2.

ההשפעה על הדף שלכם עשויה להיות דרמטית.

ההשפעה של טעינה מראש של משאבים
איור 19. ההשפעה של טעינה מראש של משאבים

בדרך כלל, בלי להשתמש ב-link rel preload, אם גופנים לדפדפן הם קריטיים לדף, הדפדפן צריך קודם לאחזר את ה-HTML, לנתח את ה-CSS, ואז, הרבה יותר מאוחר, הוא יתחיל לאחזר את הגופנים לדפדפן.

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

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

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

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

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

ניסיוני: רמזים לתעדוף

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

הגדרת העדיפות של התוכן שגלוי בהתחלה
איור 20. רמזים לגבי רמת העדיפות

זוהי תכונה חדשה שמאפשרת להעביר לרשת הדפדפן רמז לגבי מידת החשיבות של משאב. היא חושפת מאפיין חדש – importance (חשיבות) – עם הערכים low (נמוך), high (גבוה) או auto (אוטומטי).

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

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

הגדרת העדיפות של התוכן שגלוי בהתחלה
איור 21. הגדרת תעדוף לתוכן שגלוי בהתחלה

לפני שהוספנו טעינת נתונים בזמן אמת (lazy loading) לתמונות שלנו, הדפדפן היה מבצע את הפעולות הבאות: היה לנו קרוסלה של תמונות עם כל הדודלים שלנו, והדפדפן היה מאחזר את כל התמונות ממש בהתחלה של הקרוסלה עם עדיפות גבוהה בשלב מוקדם. לצערנו, התמונות שבאמצע הקרוסלה היו החשובות ביותר למשתמש. אז מה שעשינו הוא להגדיר חשיבות של תמונות הרקע האלה לרמה נמוכה מאוד, של התמונות שבחזית לגבוהה מאוד, וההשפעה שלהם על ה-3G האיטי ועל המהירות שבה הצלחנו לאחזר ולעבד את התמונות האלה. אז זאת חוויה חיובית.

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

יש לכם אסטרטגיית טעינה של גופן אינטרנט

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

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

הימנעות מטקסט בלתי נראה במהלך טעינה של גופנים באינטרנט
איור 22. נמנעים מטקסט בלתי נראה בזמן הטעינה של Web Fonts

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

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

    @font-face {
      font-family: 'Montserrat';
      font-style: normal;
      font-display: swap;
      font-weight: 400;
      src: local('Montserrat Regular'), local('Montserrat-Regular'),
          /* Chrome 26+, Opera 23+, Firefox 39+ */
          url('montserrat-v12-latin-regular.woff2') format('woff2'),
            /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
          url('montserrat-v12-latin-regular.woff') format('woff');
    }

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

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

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

תוצאה של הצגת הגופן
איור 23. תוצאת תצוגת הגופן

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

יש הרבה תכונות של פלטפורמת אינטרנט שאפשר להשתמש בהן כדי לבצע אופטימיזציה של חוויית הטעינה לגופנים, אבל כדאי גם לעיין במאגר המתכונים של גופנים באינטרנט (Web Font recipess) של Zach Leatherman, כי הוא ממש נהדר.

הפחתת מספר הסקריפטים שחוסמים את העיבוד

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

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

צמצום ההזדמנויות לגיליונות סגנונות שחוסמים את העיבוד
איור 24. צמצום ההזדמנויות של גיליונות סגנונות שגורמים לחסימת הרינדור

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

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

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

במקרה שלנו, השתמשנו במודול NPM שנקרא Critical כדי להטמיע את התוכן הקריטי ב-index.html במהלך שלב ה-build.

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

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

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

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

התוצאה

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

ציון הביצועים של Lighthouse עלה מ-23 ל-91. זו התקדמות יפה מבחינת המהירות. ביצענו בדיקה רציפה של כל השינויים בעקבות הדוח של Lighthouse. אם אתם רוצים לבדוק איך הטמענו טכנית את כל השיפורים, אתם מוזמנים להיכנס למאגר שלנו, במיוחד לבקשות העריכה (PR) שפורסמו בו.

ביצועים חזויים – חוויית משתמש מבוססת-נתונים

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

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

למעשה יש לנו נתונים זמינים שבאמצעותם אפשר לייעל את האופטימיזציה שלנו היום. באמצעות Google Analytics Reporting API אנחנו יכולים לבדוק את הדף הבא ברשימה של הדפים המובילים ואת אחוזי היציאה מכל כתובת URL באתר שלנו, וכך להסיק אילו משאבים כדאי לתת להם עדיפות.

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

חבילות מבוססות-נתונים לאפליקציות אינטרנט
איור 25. צירוף מבוסס-נתונים לאפליקציות אינטרנט

כדי להקל על הניסויים האלה, אנחנו שמחים להכריז על יוזמה חדשה שנקראת Guess.js.

Guess.js
איור 26. Guess.js

Guess.js הוא פרויקט שמתמקד בחוויות משתמש מבוססות-נתונים באינטרנט. אנחנו מקווים שהדוח הזה יניע אתכם לבדוק את האפשרות להשתמש בנתונים כדי לשפר את ביצועי האתר, וגם מעבר לכך. כל הקוד הוא קוד פתוח וזמין ב-GitHub. הכלי הזה נוצר בשיתוף פעולה עם קהילת הקוד הפתוח על ידי Minko Gechev,‏ Kyle Matthews מ-Gatsby,‏ Katie Hempenius ועוד כמה אנשים.

אנחנו מזמינים אותך לנסות את Guess.js. נשמח לשמוע מה דעתך.

סיכום

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

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

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

תודה מיוחדת ל-Ward Peeters,‏ Minko Gechev,‏ Kyle Mathews,‏ Katie Hempenius,‏ Dom Farolino,‏ Yoav Weiss,‏ Susie Lu,‏ Yusuke Utsunomiya,‏ Tom Ankers,‏ Lighthouse ו-Google Doodles.