การขยายเครื่องมือสำหรับนักพัฒนาเว็บ

ภาพรวม

ส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บจะเพิ่มฟังก์ชันการทำงานให้กับเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome โดยสามารถเพิ่มแผง UI และแถบด้านข้างใหม่ โต้ตอบกับหน้าเว็บที่ตรวจสอบ ดูข้อมูลเกี่ยวกับคำขอเครือข่าย และอื่นๆ ดูส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บที่โดดเด่น ส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บมีสิทธิ์เข้าถึงชุด API ส่วนขยายสำหรับ DevTools เพิ่มเติมโดยเฉพาะ ดังนี้

ส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บมีโครงสร้างเหมือนกับส่วนขยายอื่นๆ คืออาจมีหน้าพื้นหลัง สคริปต์เนื้อหา และรายการอื่นๆ นอกจากนี้ ส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บแต่ละรายการยังมีหน้าเครื่องมือสำหรับนักพัฒนาเว็บที่มีสิทธิ์เข้าถึง API เครื่องมือสำหรับนักพัฒนาเว็บ

แผนภาพสถาปัตยกรรมแสดงหน้าเครื่องมือสำหรับนักพัฒนาเว็บสื่อสารกับหน้าต่างที่ตรวจสอบและหน้าพื้นหลัง หน้าพื้นหลังแสดงการสื่อสารกับสคริปต์เนื้อหาและการเข้าถึง API ของส่วนขยาย
       หน้าเครื่องมือสำหรับนักพัฒนาเว็บจะมีสิทธิ์เข้าถึง API เครื่องมือสำหรับนักพัฒนาเว็บ เช่น การสร้างแผง

หน้าเครื่องมือสำหรับนักพัฒนาเว็บ

อินสแตนซ์ของหน้าเครื่องมือสำหรับนักพัฒนาเว็บของส่วนขยายจะสร้างขึ้นทุกครั้งที่หน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บเปิดขึ้น หน้าเครื่องมือสำหรับนักพัฒนาเว็บจะทำงานตลอดอายุการใช้งานของหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บ หน้าเครื่องมือสำหรับนักพัฒนาเว็บมีสิทธิ์เข้าถึง API ของ DevTools และชุด API ส่วนขยายที่จำกัด กล่าวอย่างเจาะจงก็คือ หน้าเครื่องมือสำหรับนักพัฒนาเว็บดำเนินการต่อไปนี้ได้

  • สร้างและโต้ตอบกับแผงโดยใช้ API ของ devtools.panels
  • รับข้อมูลเกี่ยวกับหน้าต่างที่ตรวจสอบและประเมินโค้ดในหน้าต่างที่ตรวจสอบโดยใช้ API ของ devtools.inspectedWindow
  • ดูข้อมูลเกี่ยวกับคำขอเครือข่ายโดยใช้ devtools.network API

หน้าเครื่องมือสำหรับนักพัฒนาเว็บใช้ API ส่วนขยายส่วนใหญ่โดยตรงไม่ได้ โดยมีสิทธิ์เข้าถึง API ของ extension และ runtime ชุดเดียวกันกับที่สคริปต์เนื้อหามีสิทธิ์เข้าถึง หน้าเครื่องมือสำหรับนักพัฒนาเว็บสื่อสารกับหน้าพื้นหลังได้โดยใช้การส่งข้อความ เช่นเดียวกับสคริปต์เนื้อหา ดูตัวอย่างได้ที่การแทรกสคริปต์เนื้อหา

การสร้างส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บ

หากต้องการสร้างหน้าเครื่องมือสำหรับนักพัฒนาเว็บสำหรับส่วนขยาย ให้เพิ่มช่อง devtools_page ในไฟล์ Manifest ของส่วนขยาย

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

ระบบจะสร้างอินสแตนซ์ของ devtools_page ที่ระบุในไฟล์ Manifest ของส่วนขยายสำหรับทุกหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บที่เปิดอยู่ หน้าเว็บดังกล่าวอาจเพิ่มหน้าส่วนขยายอื่นๆ เป็นแผงและแถบด้านข้างในหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บได้โดยใช้ devtools.panels API

โมดูล API chrome.devtools.* ใช้ได้กับหน้าที่โหลดภายในหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บเท่านั้น สคริปต์เนื้อหาและหน้าส่วนขยายอื่นๆ ไม่มี API เหล่านี้ ดังนั้น API จึงใช้ได้ตลอดอายุการใช้งานของหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บเท่านั้น

นอกจากนี้ยังมี API เครื่องมือสำหรับนักพัฒนาเว็บที่ยังอยู่ระหว่างการทดสอบด้วย โปรดดูที่ chrome.experimental* API สำหรับรายการ API ทดลองและหลักเกณฑ์วิธีใช้

องค์ประกอบ UI เครื่องมือสำหรับนักพัฒนาเว็บ: แผงและแผงแถบด้านข้าง

นอกจากองค์ประกอบ UI ของส่วนขยายตามปกติ เช่น การทำงานของเบราว์เซอร์ เมนูตามบริบท และป๊อปอัปแล้ว ส่วนขยาย DevTools ยังสามารถเพิ่มองค์ประกอบ UI ลงในหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บได้ดังนี้

  • แผงคือแท็บระดับบนสุด เช่น แผงองค์ประกอบ แหล่งที่มา และเครือข่าย
  • แผงแถบด้านข้างจะแสดง UI เสริมที่เกี่ยวข้องกับแผง แผงรูปแบบ รูปแบบที่คำนวณ และ Listener เหตุการณ์ในแผงองค์ประกอบคือตัวอย่างของแผงแถบด้านข้าง (โปรดทราบว่าหน้าตาของแผงแถบด้านข้างอาจไม่ตรงกับภาพ ทั้งนี้ขึ้นอยู่กับเวอร์ชันของ Chrome ที่คุณใช้และตำแหน่งที่วางหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บ)

หน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บที่แสดงแผงองค์ประกอบและแผงแถบด้านข้างของรูปแบบ

แต่ละแผงเป็นไฟล์ HTML ของตัวเอง ซึ่งอาจมีทรัพยากรอื่นๆ (JavaScript, CSS, รูปภาพ และอื่นๆ) การสร้างแผงพื้นฐานจะมีลักษณะดังนี้

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

JavaScript ที่ดำเนินการในแผงหรือแผงแถบด้านข้างมีสิทธิ์เข้าถึง API เดียวกันกับหน้าเครื่องมือสำหรับนักพัฒนาเว็บ

การสร้างแผงแถบด้านข้างพื้นฐานสำหรับแผงองค์ประกอบจะมีลักษณะดังนี้

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 เครื่องมือสำหรับนักพัฒนาเว็บจะประเมินนิพจน์ในบริบทของหน้าที่ตรวจสอบ และแสดงค่าที่แสดงผล

สำหรับทั้ง setObject และ setExpression แผงจะแสดงค่าตามที่จะปรากฏในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ อย่างไรก็ตาม setExpression ให้คุณแสดงองค์ประกอบ DOM และออบเจ็กต์ JavaScript ที่กำหนดเองได้ ในขณะที่ setObject รองรับเฉพาะออบเจ็กต์ JSON เท่านั้น

การสื่อสารระหว่างคอมโพเนนต์ของส่วนขยาย

ส่วนต่อไปนี้จะอธิบายสถานการณ์ทั่วไปบางส่วนสำหรับการสื่อสารระหว่างคอมโพเนนต์ต่างๆ ของส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บ

การแทรกสคริปต์เนื้อหา

หน้าเครื่องมือสำหรับนักพัฒนาเว็บไม่สามารถเรียกใช้ tabs.executeScript โดยตรง หากต้องการแทรกสคริปต์เนื้อหาจากหน้าเครื่องมือสำหรับนักพัฒนาเว็บ คุณต้องดึงรหัสของแท็บหน้าต่างที่ตรวจสอบโดยใช้พร็อพเพอร์ตี้ 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 จากหน้าเครื่องมือสำหรับนักพัฒนาเว็บ แผง หรือแผงแถบด้านข้าง

โดยค่าเริ่มต้น ระบบจะประเมินนิพจน์ในบริบทของเฟรมหลักของหน้า ตอนนี้ คุณอาจ คุ้นเคยกับฟีเจอร์ของ 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 จะไม่สร้างบริบทสคริปต์เนื้อหา คุณจึงต้องโหลดสคริปต์บริบทก่อนเรียกใช้ eval ด้วยการเรียก executeScript หรือโดยการระบุสคริปต์เนื้อหาในไฟล์ manifest.json

เมื่อมีบริบทของสคริปต์บริบทแล้ว คุณจะใช้ตัวเลือกนี้เพื่อแทรกสคริปต์เนื้อหาเพิ่มเติมได้

เมธอด eval จะมีประสิทธิภาพเมื่อใช้ในบริบทที่เหมาะสมและเป็นอันตรายเมื่อใช้ที่ไม่เหมาะสม ใช้เมธอด tabs.executeScript หากไม่ต้องการเข้าถึงบริบท JavaScript ของหน้าที่ตรวจสอบ ดูข้อควรระวังโดยละเอียดและการเปรียบเทียบทั้ง 2 วิธีได้ที่ inspectedWindow

การส่งองค์ประกอบที่เลือกไปยังสคริปต์เนื้อหา

สคริปต์เนื้อหาไม่มีสิทธิ์เข้าถึงองค์ประกอบที่เลือกปัจจุบันโดยตรง แต่โค้ดที่คุณเรียกใช้โดยใช้ inspectedWindow.eval จะมีสิทธิ์เข้าถึงคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บและ API บรรทัดคำสั่ง เช่น ในโค้ดที่ได้รับการประเมิน คุณจะใช้ $0 เพื่อเข้าถึงองค์ประกอบที่เลือกได้

วิธีส่งองค์ประกอบที่เลือกไปยังสคริปต์เนื้อหา

  • สร้างเมธอดในสคริปต์เนื้อหาซึ่งจะใช้องค์ประกอบที่เลือกเป็นอาร์กิวเมนต์
  • เรียกใช้เมธอดจากหน้าเครื่องมือสำหรับนักพัฒนาเว็บโดยใช้ 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 ซึ่งจะส่งข้อความไปยังสคริปต์เนื้อหาในแท็บที่ระบุ ดังที่แสดงในการแทรกสคริปต์เนื้อหา

เมื่อส่งข้อความจากสคริปต์เนื้อหา จะไม่มีวิธีการแบบสำเร็จรูปในการส่งข้อความไปยังอินสแตนซ์ของหน้าเครื่องมือสำหรับนักพัฒนาเว็บที่ถูกต้องซึ่งเชื่อมโยงกับแท็บปัจจุบัน ในการแก้ปัญหาชั่วคราว คุณอาจให้หน้าเครื่องมือสำหรับนักพัฒนาเว็บสร้างการเชื่อมต่อที่มีระยะเวลานานกับหน้าพื้นหลัง และให้หน้าพื้นหลังเก็บแมปของรหัสแท็บไปยังการเชื่อมต่อ เพื่อให้กำหนดเส้นทางแต่ละข้อความไปยังการเชื่อมต่อที่ถูกต้องได้

// 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 จะไม่ส่งข้อความไปยังสคริปต์พื้นหลังตามที่คาดไว้

ในการแก้ปัญหาชั่วคราว คุณอาจรวมสคริปต์ที่แทรกเข้ามากับสคริปต์เนื้อหาที่ทำหน้าที่เป็นสื่อกลาง คุณใช้ window.postMessage API เพื่อส่งข้อความไปยังสคริปต์เนื้อหาได้ ต่อไปนี้เป็นตัวอย่าง โดยสมมติว่าสคริปต์พื้นหลังจากส่วนก่อนหน้า:

// 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);
});

ข้อความจะเริ่มจากสคริปต์ที่แทรกไปยังสคริปต์เนื้อหา ไปยังสคริปต์พื้นหลัง และสุดท้ายก็ไปที่หน้าเครื่องมือสำหรับนักพัฒนาเว็บ

นอกจากนี้ คุณยังพิจารณาเทคนิคการส่งข้อความทางเลือก 2 แบบได้ที่นี่

ตรวจจับการเปิดและปิดเครื่องมือสำหรับนักพัฒนาเว็บ

หากส่วนขยายต้องการติดตามว่าหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บเปิดอยู่หรือไม่ คุณสามารถเพิ่มโปรแกรมฟัง onConnect ไปยังหน้าเบื้องหลัง และเรียกใช้เชื่อมต่อจากหน้าเครื่องมือสำหรับนักพัฒนาเว็บ เนื่องจากแต่ละแท็บสามารถเปิดหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บของตัวเองได้ คุณจึงอาจได้รับเหตุการณ์การเชื่อมต่อหลายเหตุการณ์ หากต้องการติดตามว่าหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บเปิดอยู่หรือไม่ คุณต้องนับเหตุการณ์การเชื่อมต่อและยกเลิกการเชื่อมต่อดังที่แสดงด้านล่าง

// 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"
});

ตัวอย่างส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บ

เรียกดูแหล่งที่มาของตัวอย่างส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บเหล่านี้:

ข้อมูลเพิ่มเติม

ดูข้อมูลเกี่ยวกับ API มาตรฐานที่ส่วนขยายใช้ได้ที่หัวข้อ chrome* API และ API บนเว็บ

ส่งความคิดเห็นถึงเรา ความคิดเห็นและคำแนะนำของคุณจะช่วยเราปรับปรุง API ได้

ตัวอย่าง

คุณดูตัวอย่างที่ใช้ DevTools API ได้ในตัวอย่าง