הפחתת מטענים ייעודיים (payloads) של JavaScript באמצעות פיצול קוד

אף אחד לא אוהב לחכות. יותר מ-50% מהמשתמשים נוטשים את האתר אם הטעינה שלו נמשכת יותר מ-3 שניות.

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

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

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

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

בהתאם לארכיטקטורה של האתר – במיוחד אם האתר מסתמך במידה רבה על עיבוד בצד הלקוח – הפחתת הגודל של עומסי העבודה של JavaScript שאחראים לעיבוד ה-Markup עשויה להוביל לשיפור זמני Largest Contentful Paint‏ (LCP). מצב כזה יכול לקרות במקרים שבהם משאב ה-LCP מתעכב במציאת רכיב ה-LCP עד שמסיימים את תגי העיצוב בצד הלקוח, או כשה-thread הראשי עמוס מדי ולא מאפשר לעבד את רכיב ה-LCP הזה. שני התרחישים האלה עלולים לעכב את זמן ה-LCP של הדף.

מדידה

ב-Lighthouse מוצגת ביקורת שנכשלה כשנדרש הרבה זמן לביצוע כל ה-JavaScript בדף.

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

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

חבילות מודולים פופולריות כמו webpack,‏ Parcel ו-Rollup מאפשרות לפצל את החבילות באמצעות ייבוא דינמי. לדוגמה, קטע הקוד הבא מציג דוגמה ל-method someFunction שמופעלת כשטופס נשלח.

import moduleA from "library";

form.addEventListener("submit", e => {
  e.preventDefault();
  someFunction();
});

const someFunction = () => {
  // uses moduleA
}

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

form.addEventListener("submit", e => {
  e.preventDefault();
  import('library.moduleA')
    .then(module => module.default) // using the default export
    .then(() => someFunction())
    .catch(handleError());
});

const someFunction = () => {
    // uses moduleA
}

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

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

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