ניפוי באגים מודרני באינטרנט בכלי הפיתוח ל-Chrome

מבוא

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

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

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

  • אתם לא רוצים לנפות באגים בקוד JavaScript מצומצם, אתם רוצים לנפות באגים בקוד JavaScript המקורי.
  • כשמשתמשים ב-TypeScript, לא רוצים לנפות באגים ב-JavaScript, אלא לנפות באגים בקוד TypeScript המקורי.
  • כשמשתמשים בתבניות כמו Angular, Lit או JSX, לא תמיד כדאי לנפות באגים ב-DOM שנוצר. מומלץ לנפות באגים ברכיבים עצמם.

באופן כללי, מומלץ לנפות באגים בקוד שלכם כפי שכתבתם אותו.

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

בואו נראה!

קוד שנוצר לעומת קוד שנפרס

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

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

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

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

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

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

צילום מסך של ההגדרות של DevTools.

'רק הקוד שלי'

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

כדי לפצות על כך, ב-DevTools יש הגדרה נוספת שמופעלת כברירת מחדל: הוספת סקריפטים ידועים של צד שלישי באופן אוטומטי לרשימת הפריטים להתעלמות. אפשר למצוא אותו בקטע DevTools‏ > Settings‏ > Ignore List.

צילום מסך של הגדרות כלי הפיתוח.

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

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

ככותב/ת, לא צריך לעשות דבר כדי לאפשר את ההתנהגות החדשה הזו. יישום השינוי הזה נקבע על ידי ה-framework.

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

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

צילום מסך של מעקב סטאק ב-DevTools.

אם רוצים לראות את כל מסגרות הקריאה של ניתוח ה-stack, תמיד אפשר ללחוץ על הקישור Show more frames.

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

צילום מסך של הכלי לניפוי באגים של מקורות ב-DevTools במהלך ניפוי הבאגים.

קוד שנבחר להתעלמות בעץ הקבצים

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

צילום מסך של הגדרות כלי הפיתוח.

בפרויקט Angular לדוגמה, התיקיות node_modules ו-webpack מוסתרות עכשיו.

צילום מסך של עץ הקבצים ב-Chrome DevTools שבו מוצג הקוד שנכתב על ידי המחבר, אבל לא מוצגים הקבצים של node_modules.

קוד שמופיע ברשימה להתעלמות בתפריט 'פתיחה מהירה'

קוד שמופיע ברשימה של קוד שאפשר להתעלם ממנו מוסתר לא רק בעץ הקבצים, אלא גם בתפריט 'פתיחה מהירה' (‎Control+‎P (Linux/Windows) או ‎Command+‎P (Mac)).

צילום מסך של כלי הפיתוח עם התפריט 'פתיחה מהירה'.

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

כבר דיברנו על עקבות סטאק רלוונטיות, אבל ב-Chrome DevTools יש עוד שיפורים בעקבות סטאק.

מעקב קריאות מקושר

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

לדוגמה, הנה תזמון פשוט מאוד בקובץ framework.js היפותטי:

function makeScheduler() {
  const tasks = [];

  return {
    schedule(f) {
      tasks.push({ f });
    },

    work() {
      while (tasks.length) {
        const { f } = tasks.shift();
        f();
      }
    },
  };
}

const scheduler = makeScheduler();

function loop() {
  scheduler.work();
  requestAnimationFrame(loop);
};

loop();

... ואיך המפתח עשוי להשתמש בו בקוד שלו בקובץ example.js:

function someTask() {
  console.trace("done!");
}

function businessLogic() {
  scheduler.schedule(someTask);
}

businessLogic();

כשמוסיפים נקודת עצירה בתוך שיטת someTask או כשבודקים את המעקב שמודפס במסוף, לא מופיעה אזכור של הקריאה ל-businessLogic() שהיא "הגורם הבסיסי" של הפעולה הזו.

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

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

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

ה-API Async Stack Tagging API כולל שיטת console חדשה בשם console.createTask(). חתימת ה-API היא:

interface Console {
  createTask(name: string): Task;
}

interface Task {
  run<T>(f: () => T): T;
}

הקריאה console.createTask() מחזירה מכונה Task שאפשר להשתמש בה בהמשך כדי להריץ את תוכן המשימה f.

// Task Creation
const task = console.createTask(name);

// Task Execution
task.run(f);

המשימה יוצרת את הקישור בין ההקשר שבו היא נוצרה לבין ההקשר של הפונקציה האסינכרונית שמופעלת.

כשמחילים את הפונקציה makeScheduler שלמעלה, הקוד הופך לזה:

function makeScheduler() {
  const tasks = [];

  return {
    schedule(f) {
      const task = console.createTask(f.name);
      tasks.push({ task, f });
    },

    work() {
      while (tasks.length) {
        const { task, f } = tasks.shift();
        task.run(f); // instead of f();
      }
    },
  };
}

בזכות זה, כלי הפיתוח ל-Chrome יכולים להציג דוח קריסות טוב יותר.

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

שימו לב ש-businessLogic() נכלל עכשיו ב-stack trace. בנוסף, למשימה יש שם מוכר someTask במקום השם הגנרי requestAnimationFrame כמו בעבר.

מסגרות ידידותיות לשיחות

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

בדוגמה לפרויקט, דוגמה לכך היא AppComponent_Template_app_button_handleClick_1_listener שמופיעה ב-stack trace.

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

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

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

במבט קדימה

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

צוות Chrome DevTools ממליץ למפתחי מסגרות להשתמש ביכולות החדשות האלה. במאמר מקרה לדוגמה: Better Angular Debugging באמצעות כלי פיתוח תוכלו למצוא הנחיות להטמעה.