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

ภาพรวม

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • แผงคือแท็บระดับบนสุด เช่น แผงองค์ประกอบ แหล่งที่มา และเครือข่าย
  • แผงแถบด้านข้างแสดง UI เสริมที่เกี่ยวข้องกับแผง แผงสไตล์ รูปแบบที่คำนวณแล้ว และ Listeners เหตุการณ์ในแผงองค์ประกอบเป็นตัวอย่างของแผงด้านข้าง (โปรดทราบว่าลักษณะที่ปรากฏของแผงแถบด้านข้างอาจไม่ตรงกับรูปภาพ ทั้งนี้ขึ้นอยู่กับเวอร์ชันของ 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 DevTools จะประเมินนิพจน์ในบริบทของหน้าเว็บที่ตรวจสอบ และแสดงผลลัพธ์

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

การสื่อสารระหว่างคอมโพเนนต์ชิ้นงาน

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

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

หน้าเครื่องมือสำหรับนักพัฒนาเว็บเรียก 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() ใช้บริบทและตัวเลือกการเรียกใช้สคริปต์เดียวกันกับโค้ดที่พิมพ์ในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ ซึ่งช่วยให้เข้าถึง API เหล่านี้ภายใน eval ได้ ตัวอย่างเช่น SOAK ใช้ Inspect Element ดังนี้

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

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

เมธอด 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จากแผงเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ คุณจะต้องมีข้อมูลอ้างอิงถึงออบเจ็กต์ window ของแผงนั้น รับหน้าต่าง iframe ของแผงจากเครื่องจัดการเหตุการณ์ panel.onShown

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

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

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

เมื่อส่งข้อความไปยังสคริปต์เนื้อหา หน้าเบื้องหลังจะใช้เมธอด tabs.sendMessage ได้ ซึ่งจะส่งข้อความไปยังสคริปต์เนื้อหาในแท็บที่เฉพาะเจาะจง ดังที่แสดงในการแทรกสคริปต์เนื้อหา

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

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

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

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

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

ตัวอย่าง

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