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

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

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

למה פיצול קוד מועיל?

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

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

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

מדידה

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

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

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

מקבצי מודולים פופולריים כמו webpack, Parcel ו-Rollup מאפשרים לפצל את החבילות באמצעות ייבוא דינמי. לדוגמה, קטע הקוד הבא מראה דוגמה לשיטה 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 יכול לעזור לכם לעשות זאת.

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