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

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

צילום מסך של אפליקציה

מדידה

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

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

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

  1. מקישים על 'Control+Shift+J' (או על 'Command+Option+J' ב-Mac) כדי לפתוח את כלי הפיתוח.
  2. לוחצים על הכרטיסייה רשתות.
  3. מסמנים את התיבה Disable cache (השבתת מטמון).
  4. טוענים מחדש את האפליקציה.

גודל החבילה המקורי: 992KB

קוד JavaScript בנפח של כמעט 1MB נשלח כדי לטעון אפליקציה פשוטה זו.

כדאי לקרוא את האזהרות על הפרויקט בכלי הפיתוח.

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

מסנן אזהרות

  • קוראים את האזהרה שמוצגת.

אזהרה לגבי המסוף

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

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

ניתוח החבילה

באפליקציה יש שני יחסי תלות עיקריים:

  • Firebase: פלטפורמה שמספקת כמה שהם שימושיים ל-iOS, ל-Android או לאפליקציות אינטרנט. כאן המיקום זמן אמת מסד נתונים משמש לאחסן ולסנכרן את המידע של כל חתלתול בזמן אמת.
  • Moment.js: ספריית כלי עזר שמאפשרת לטפל בתאריכים ב-JavaScript. תאריך הלידה של כל חתלתול שמור מסד הנתונים של Firebase ו-moment משמש לחישוב הגיל שלו בשבועות.

איך רק שני יחסי תלות יכולים לתרום לגודל חבילה של כמעט 1MB? ובכן, אחת הסיבות לכך היא שלכל תלות יכולה להיות כך שיש הרבה יותר משתיים, אם כל עומק/הסתעפות "עץ" של תלות מובאת בחשבון. קל לאפליקציות להגדיל מהר יחסית אם כלולים יחסי תלות רבים.

צריך לנתח את ה-bundler כדי להבין טוב יותר מה קורה. יש כמה כלים שונים שנוצרו על ידי הקהילה שיכולים לעזור לעשות את זה, כמו webpack-bundle-analyzer

החבילה של הכלי הזה כבר כלולה באפליקציה בתור devDependency.

"devDependencies": {
  //...
  "webpack-bundle-analyzer": "^2.13.1"
},

המשמעות היא שניתן להשתמש בו ישירות בקובץ התצורה של ה-webpack. אפשר לייבא אותו בתחילת webpack.config.js:

const path = require("path");

//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

עכשיו מוסיפים אותו כפלאגין בסוף הקובץ בתוך המערך plugins:

module.exports = {
  //...
  plugins: [
    //...
    new BundleAnalyzerPlugin()
  ]
};

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

כלי לניתוח חבילות של Webpack

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

גודל נתונים סטטיסטיים גודל לפני הקטנה או דחיסה.
גודל ניתוח גודל החבילה בפועל בתוך החבילה לאחר ההרכבה. גרסה 4 של Webpack (שבה משתמשים באפליקציה הזו) מקטינה של קבצים שעברו הידור באופן אוטומטי ולכן זה קטן יותר מהנתון הסטטיסטי גודל.
גודל קובץ Gzip גודל החבילה לאחר שהיא דחוסה באמצעות קידוד gzip. הזה נושא מסוים מוסבר במדריך נפרד.

בעזרת הכלי webpack-bundle-analyzer קל יותר לזהות תכנים שלא נמצאים בשימוש חבילות שאינן נחוצות שמהוות אחוז גדול מהחבילה.

הסרה של חבילות שלא נמצאות בשימוש

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

  • firestore
  • auth
  • storage
  • messaging
  • functions

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

ביטול השינויים שבוצעו ב-webpack.config.js כדי לראות שוב את האפליקציה:

  • הסרה של BundleAnalyzerPlugin מרשימת יישומי הפלאגין:
plugins: [
  //...
  new BundleAnalyzerPlugin()
];
  • עכשיו מסירים את הייבוא שלא נמצא בשימוש מהחלק העליון של הקובץ:
const path = require("path");

//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

האפליקציה אמורה להיטען כרגיל עכשיו. יש לשנות את src/index.js כדי לעדכן את ייבוא מ-Firebase.

import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';

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

גודל החבילה הוקטן ל-480KB

הוסרו יותר ממחצית מגודל החבילה. ב-Firebase יש הרבה אפשרויות ומספקת למפתחים את האפשרות לכלול רק את אלה הדרושים. באפליקציה הזו, רק firebase/database שימש לאחסון ולסנכרון כל הנתונים. הייבוא firebase/app, שמגדיר את פלטפורמת ה-API עבור כל אחד מהשירותים השונים, הוא תמיד נדרש.

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

למרות שגודל החבילה הופחת קצת, אבל יש עוד הרבה יותר. לעשות את העבודה. 😈

הסרת חבילות לא נחוצות

בניגוד ל-Firebase, לא ניתן לייבא חלקים מהספרייה של moment בתור בקלות, אבל ייתכן שניתן יהיה להסיר אותה לגמרי?

יום ההולדת של כל חתלתול חמוד נשמר בפורמט Unix (אלפיות שנייה) מסד הנתונים ב-Firebase.

תאריכי לידה שמאוחסנים בפורמט Unix

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

כמו תמיד, מומלץ לא להעתיק ולהדביק את פרטי המעקב של הסרטונים שנמצאים כאן. צריך להתחיל ב- מסירה את moment מהייבוא של src/index.js.

import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';

יש מעבד אירועים של Firebase שמטפל בשינויים בערכים במסד הנתונים שלנו:

favoritesRef.on("value", (snapshot) => { ... })

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

const ageInWeeks = birthDate => {
  const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
  const diff = Math.abs((new Date).getTime() - birthDate);
  return Math.floor(diff / WEEK_IN_MILLISECONDS);
}

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

לבסוף, אפשר להסיר את כל המופעים של moment ב-event listener על ידי שימוש בפונקציה הזו במקום:

favoritesRef.on("value", (snapshot) => {
  const { kitties, favorites, names, birthDates } = snapshot.val();
  favoritesScores = favorites;

  kittiesList.innerHTML = kitties.map((kittiePic, index) => {
    const birthday = moment(birthDates[index]);

    return `
      <li>
        <img src=${kittiePic} onclick="favKittie(${index})">
        <div class="extra">
          <div class="details">
            <p class="name">${names[index]}</p>
            <p class="age">${moment().diff(birthday, 'weeks')} weeks old</p>
            <p class="age">${ageInWeeks(birthDates[index])} weeks old</p>
          </div>
          <p class="score">${favorites[index]} ❤</p>
        </div>
      </li>
    `})
});

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

גודל החבילה הוקטן ל-225KB

גודל החבילה שלנו הופחת ביותר מחצי.

סיכום

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

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

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

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