הרחבת כלי הפיתוח

סקירה כללית

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

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

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

הדף של כלי הפיתוח

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

  • יצירת לוחות ואינטראקציה איתם באמצעות ממשקי ה-API של devtools.panels.
  • קבלת מידע על החלון שנבדק והערכת קוד בחלון שנבדק באמצעות ממשקי ה-API של devtools.inspectedWindow.
  • קבלת מידע על בקשות רשת באמצעות ממשקי ה-API של devtools.network.

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

יצירת תוסף ל-DevTools

כדי ליצור דף DevTools לתוסף, מוסיפים את השדה devtools_page למניפסט של התוסף:

{
  "name": ...
  "version": "1.0",
  "minimum_chrome_version": "10.0",
  "devtools_page": "devtools.html",
  ...
}

מופע של devtools_page שצוין במניפסט של התוסף נוצר לכל חלון DevTools שנפתח. הדף יכול להוסיף דפי תוספים אחרים כחלוניות וסרגלי צד לחלון DevTools באמצעות ה-API devtools.panels.

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

יש גם כמה ממשקי API של DevTools שעדיין נמצאים בגרסת בטא. אפשר לעיין במאמר בנושא chrome.experimental.* API כדי לראות את רשימת ממשקי ה-API הניסיוניים ואת ההנחיות לשימוש בהם.

רכיבי ממשק המשתמש של DevTools: חלוניות וחלוניות צד

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

  • חלונית היא כרטיסייה ברמה העליונה, כמו החלוניות Elements (רכיבים), Sources (מקורות) ו-Network (רשת).
  • חלונית בסרגל הצד מציגה ממשק משתמש משלים שקשור לחלונית. חלוניות הסגנונות, הסגנונות המחושבים והאזנות לאירועים בחלונית הרכיבים הן דוגמאות לחלוניות בסרגל הצד. (שימו לב שהמראה של החלוניות בסרגל הצד עשוי להיות שונה מהתמונה, בהתאם לגרסה של Chrome שבה אתם משתמשים ולמיקום של חלון DevTools.)

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

כל חלונית היא קובץ HTML משלה, שיכול לכלול משאבים אחרים (JavaScript,‏ CSS, תמונות וכו'). כך יוצרים חלונית בסיסית:

chrome.devtools.panels.create("My Panel",
    "MyPanelIcon.png",
    "Panel.html",
    function(panel) {
      // code invoked on panel creation
    }
);

ל-JavaScript שמופעל בחלונית או בחלונית הצדדית יש גישה לאותם ממשקי API שיש לדף DevTools.

כך יוצרים חלונית בסיסית בסרגל הצד של חלונית הרכיבים:

chrome.devtools.panels.elements.createSidebarPane("My Sidebar",
    function(sidebar) {
        // sidebar initialization code here
        sidebar.setObject({ some_data: "Some data to show" });
});

יש כמה דרכים להציג תוכן בחלונית של סרגל הצד:

  • תוכן HTML. קוראים לפונקציה setPage כדי לציין דף HTML שיוצג בחלונית.
  • נתוני JSON. מעבירים אובייקט JSON אל setObject.
  • ביטוי JavaScript. מעבירים ביטוי אל setExpression. DevTools מעריך את הביטוי בהקשר של הדף שנבדק ומציג את ערך ההחזרה.

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

תקשורת בין רכיבי התוסף

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

החדרת סקריפט של תוכן

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

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

// DevTools page -- devtools.js
// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "devtools-page"
});

backgroundPageConnection.onMessage.addListener(function (message) {
    // Handle responses from the background page, if any
});

// Relay the tab ID to the background page
chrome.runtime.sendMessage({
    tabId: chrome.devtools.inspectedWindow.tabId,
    scriptToInject: "content_script.js"
});

הקוד של דף הרקע:

// Background page -- background.js
chrome.runtime.onConnect.addListener(function(devToolsConnection) {
    // assign the listener function to a variable so we can remove it later
    var devToolsListener = function(message, sender, sendResponse) {
        // Inject a content script into the identified tab
        chrome.tabs.executeScript(message.tabId,
            { file: message.scriptToInject });
    }
    // add the listener
    devToolsConnection.onMessage.addListener(devToolsListener);

    devToolsConnection.onDisconnect.addListener(function() {
         devToolsConnection.onMessage.removeListener(devToolsListener);
    });
});

הערכה של JavaScript בחלון שנבדק

אפשר להשתמש בשיטה inspectedWindow.eval כדי להריץ קוד JavaScript בהקשר של הדף שנבדק. אפשר להפעיל את השיטה eval מדף, מחלונית או מחלונית צדדית של DevTools.

כברירת מחדל, הביטוי מחושב בהקשר של המסגרת הראשית של הדף. יכול להיות שאתם מכירים את התכונות של Commandline API ב-DevTools, כמו בדיקת רכיבים (inspect(elem)), הפסקה בפונקציות (debug(fn)), העתקה ללוח העריכה (copy()) ועוד. ב-inspectedWindow.eval() נעשה שימוש באותן אפשרויות ובאותו הקשר של הרצת הסקריפט כמו בקוד שהקלדתם במסוף DevTools, וכך מתאפשרת גישה לממשקי ה-API האלה בתוך הפונקציה eval. לדוגמה, SOAK משתמש בו כדי לבדוק רכיב:

chrome.devtools.inspectedWindow.eval(
  "inspect($$('head script[data-soak=main]')[0])",
  function(result, isException) { }
);

לחלופין, אפשר להשתמש באפשרות useContentScriptContext: true עבור inspectedWindow.eval() כדי להעריך את הביטוי באותו הקשר שבו נמצאים סקריפטים של תוכן. קריאה ל-eval עם useContentScriptContext: true לא create הקשר של סקריפט תוכן, לכן צריך לטעון סקריפט הקשר לפני שמפעילים את eval, על ידי קריאה ל-executeScript או על ידי ציון סקריפט תוכן בקובץ manifest.json.

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

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

העברת הרכיב שנבחר לסקריפט תוכן

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

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

  • יוצרים שיטת קוד בסקריפט התוכן שמקבלת את הרכיב שנבחר כארגומנטים.
  • קוראים ל-method מדף כלי הפיתוח באמצעות inspectedWindow.eval עם האפשרות useContentScriptContext: true.

הקוד בסקריפט התוכן עשוי להיראות כך:

function setSelectedElement(el) {
    // do something with the selected element
}

מפעילים את השיטה מדף כלי הפיתוח כך:

chrome.devtools.inspectedWindow.eval("setSelectedElement($0)",
    { useContentScriptContext: true });

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

אחזור של window של חלונית עזר

כדי postMessage מחלונית של devtools, צריך הפניה לאובייקט window שלה. אחזור חלון iframe של חלונית מתוך גורם הטיפול באירועים panel.onShown:

onShown.addListener(function callback)
extensionPanel.onShown.addListener(function (extPanelWindow) {
    extPanelWindow instanceof Window; // true
    extPanelWindow.postMessage( // …
});

שליחת הודעות מסקריפטים של תוכן לדף של כלי הפיתוח

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

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

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

// background.js
var connections = {};

chrome.runtime.onConnect.addListener(function (port) {

    var extensionListener = function (message, sender, sendResponse) {

        // The original connection event doesn't include the tab ID of the
        // DevTools page, so we need to send it explicitly.
        if (message.name == "init") {
          connections[message.tabId] = port;
          return;
        }

    // other message handling
    }

    // Listen to messages sent from the DevTools page
    port.onMessage.addListener(extensionListener);

    port.onDisconnect.addListener(function(port) {
        port.onMessage.removeListener(extensionListener);

        var tabs = Object.keys(connections);
        for (var i=0, len=tabs.length; i < len; i++) {
          if (connections[tabs[i]] == port) {
            delete connections[tabs[i]]
            break;
          }
        }
    });
});

// Receive message from content script and relay to the devTools page for the
// current tab
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    // Messages from content scripts should have sender.tab set
    if (sender.tab) {
      var tabId = sender.tab.id;
      if (tabId in connections) {
        connections[tabId].postMessage(request);
      } else {
        console.log("Tab not found in connection list.");
      }
    } else {
      console.log("sender.tab not defined.");
    }
    return true;
});

הדף של כלי הפיתוח (או החלונית או חלונית הצד) יוצר את החיבור באופן הבא:

// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "panel"
});

backgroundPageConnection.postMessage({
    name: 'init',
    tabId: chrome.devtools.inspectedWindow.tabId
});

שליחת הודעות מסקריפטים מוחדרים לדף של כלי הפיתוח

הפתרון שלמעלה מתאים לסקריפטים של תוכן, אבל קוד שמוזן ישירות לדף (למשל, באמצעות צירוף תג <script> או באמצעות inspectedWindow.eval) דורש שיטה אחרת. בהקשר הזה, runtime.sendMessage לא יעביר הודעות לסקריפט הרקע כמצופה.

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

// injected-script.js

window.postMessage({
  greeting: 'hello there!',
  source: 'my-devtools-extension'
}, '*');
// content-script.js

window.addEventListener('message', function(event) {
  // Only accept messages from the same frame
  if (event.source !== window) {
    return;
  }

  var message = event.data;

  // Only accept messages that we know are ours
  if (typeof message !== 'object' || message === null ||
      !message.source === 'my-devtools-extension') {
    return;
  }

  chrome.runtime.sendMessage(message);
});

עכשיו ההודעה תעבור מהסקריפט שהוזן, לסקריפט התוכן, לסקריפט הרקע ולבסוף לדף DevTools.

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

זיהוי של פתיחה וסגירה של כלי הפיתוח

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

// background.js
var openCount = 0;
chrome.runtime.onConnect.addListener(function (port) {
    if (port.name == "devtools-page") {
      if (openCount == 0) {
        alert("DevTools window opening.");
      }
      openCount++;

      port.onDisconnect.addListener(function(port) {
          openCount--;
          if (openCount == 0) {
            alert("Last DevTools window closing.");
          }
      });
    }
});

דף כלי הפיתוח יוצר חיבור כזה:

// devtools.js

// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "devtools-page"
});

דוגמאות לתוספים של כלי הפיתוח

אפשר לעיין במקורות של דוגמאות התוספים הבאות ל-DevTools:

  • Polymer Devtools Extension – הכלי משתמש בהרבה פונקציות עזר שפועלות בדף המארח כדי לשלוח שאילתה לגבי מצב DOM/JS ולשלוח אותו חזרה לחלונית בהתאמה אישית.
  • תוסף React DevTools – משתמש במודול משנה של Blink כדי לעשות שימוש חוזר ברכיבים של ממשק המשתמש של DevTools.
  • Ember Inspector – ליבה משותפת של תוסף עם מתאמים ל-Chrome ול-Firefox.
  • Coquette-inspect – תוסף נקי מבוסס-React עם סוכן ניפוי באגים שמוחדר לדף המארח.
  • בגלריית התוספים של DevTools ובתוספים לדוגמה יש אפליקציות נוספות ששווה להתקין, לנסות וללמוד מהן.

מידע נוסף

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

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

דוגמאות

דוגמאות לשימוש בממשקי API של DevTools זמינות בקטע דוגמאות.