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

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

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

API ส่วนขยายเฉพาะ DevTools มีดังนี้

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

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

  • สร้างและโต้ตอบกับแผงโดยใช้ devtools.panels API ซึ่งรวมถึงการเพิ่มหน้าส่วนขยายอื่นๆ เป็นแผงหรือแถบด้านข้างในหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บ
  • รับข้อมูลเกี่ยวกับหน้าต่างที่ตรวจสอบและประเมินโค้ดในหน้าต่างที่ตรวจสอบโดยใช้ API ของ devtools.inspectedWindow
  • ดูข้อมูลเกี่ยวกับคำขอเครือข่ายโดยใช้ API ของ devtools.network
  • ขยายแผงโปรแกรมอัดเสียงโดยใช้ API ของ devtools.recorder
  • รับข้อมูลเกี่ยวกับสถานะการบันทึกของแผงประสิทธิภาพโดยใช้ API ของ devtools.performance

หน้าเครื่องมือสำหรับนักพัฒนาเว็บสามารถเข้าถึง API ของส่วนขยายได้โดยตรง ซึ่งรวมถึงความสามารถในการสื่อสารกับ Service Worker โดยใช้การส่งข้อความ

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

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

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

ฟิลด์ devtools_page ต้องชี้ไปยังหน้า HTML เนื่องจากหน้า DevTools ต้องอยู่ในเครื่องของส่วนขยาย เราจึงขอแนะนำให้คุณระบุโดยใช้ URL ที่เกี่ยวข้อง

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

เนมสเปซของเบราว์เซอร์และส่วนขยาย DevTools

ระบบจะปิดbrowserเนมสเปซ ที่เปิดตัวใน Chrome 148 สำหรับส่วนขยายที่ประกาศ devtools_page การเลือกไม่ใช้จะมีผลกับส่วนขยายทั้งหมด ไม่ใช่แค่หน้า DevTools แต่จะมีผลกับบริบทสคริปต์ทั้งหมดที่ API ของส่วนขยายทำงาน ใช้ chrome.* ต่อไปในส่วนขยายเหล่านี้

สาเหตุคือความเข้ากันได้กับ webextension-polyfill chrome.devtools.* API เป็นแบบเรียกกลับเท่านั้น ซึ่งยังไม่แสดงผล Promise โดยกำเนิด ดังนั้นส่วนขยายเครื่องมือสำหรับนักพัฒนาเว็บจึงมักต้องใช้ Polyfill เพื่อห่อหุ้ม API เหล่านี้ Polyfill จะข้ามการห่อเมื่อใดก็ตามที่มีการกำหนด browser โดยถือว่าโฮสต์ได้ทำงานดังกล่าวแล้ว หาก Chrome เปิดใช้ browser สำหรับส่วนขยายเหล่านี้ Polyfill จะไม่ดำเนินการใดๆ และการเรียก chrome.devtools.* จะหยุดแสดงผล Promise การปิด browser จะทำให้ Polyfill ยังคงห่อหุ้มต่อไป

การเลือกไม่ใช้เดียวกันนี้จะปิดใช้การเปลี่ยนแปลงอื่นๆ ใน Chrome 148 Messaging API สำหรับส่วนขยายเหล่านี้ด้วย ซึ่งรวมถึง การตอบกลับ Promise ใน runtime.onMessage เราจะยกเลิกข้อจำกัดนี้เมื่อ API ของเครื่องมือสำหรับนักพัฒนาเว็บรองรับ Promise โดยค่าเริ่มต้น

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

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

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

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

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

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

หากต้องการแทรก Content Script ให้ใช้ scripting.executeScript()

// DevTools page -- devtools.js
chrome.scripting.executeScript({
  target: {
    tabId: chrome.devtools.inspectedWindow.tabId
  },
  files: ["content_script.js"]
});

คุณสามารถดึงรหัสแท็บของหน้าต่างที่ตรวจสอบได้โดยใช้พร็อพเพอร์ตี้ inspectedWindow.tabId

หากมีการแทรก Content Script แล้ว คุณสามารถใช้ Messaging API เพื่อ สื่อสารกับ Content Script นั้นได้

ประเมิน JavaScript ในหน้าต่างที่ตรวจสอบ

คุณสามารถใช้วิธี inspectedWindow.eval() เพื่อเรียกใช้โค้ด JavaScript ในบริบทของหน้าเว็บที่ตรวจสอบ คุณเรียกใช้เมธอด eval() จากหน้าเครื่องมือสำหรับนักพัฒนาเว็บ แผง หรือแผงแถบด้านข้างได้

โดยค่าเริ่มต้น ระบบจะประเมินนิพจน์ในบริบทของเฟรมหลักของหน้าเว็บ inspectedWindow.eval() ใช้บริบทและตัวเลือกการเรียกใช้สคริปต์เดียวกันกับโค้ด ที่ป้อนในคอนโซลเครื่องมือสำหรับนักพัฒนาเว็บ ซึ่งช่วยให้เข้าถึงฟีเจอร์ API ของยูทิลิตีคอนโซลของเครื่องมือสำหรับนักพัฒนาเว็บได้เมื่อใช้ eval() ตัวอย่างเช่น ใช้เพื่อตรวจสอบองค์ประกอบสคริปต์แรกภายในส่วน <head> ของเอกสาร HTML

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

นอกจากนี้ คุณยังตั้งค่า useContentScriptContext เป็น true เมื่อเรียกใช้ inspectedWindow.eval() เพื่อ ประเมินนิพจน์ในบริบทเดียวกันกับ Content Script ได้ด้วย หากต้องการใช้ตัวเลือกนี้ ให้ใช้การประกาศสคริปต์เนื้อหาแบบคงที่ก่อนเรียกใช้ eval() โดยเรียกใช้ executeScript() หรือระบุเนื้อหาสคริปต์ในไฟล์ manifest.json หลังจากโหลดบริบทของ Content Script แล้ว คุณยังใช้ตัวเลือกนี้เพื่อ แทรก Content Script เพิ่มเติมได้ด้วย

ส่งองค์ประกอบที่เลือกไปยัง Content Script

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

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

  1. สร้างเมธอดใน Content Script ที่รับองค์ประกอบที่เลือกเป็นอาร์กิวเมนต์

    function setSelectedElement(el) {
        // do something with the selected element
    }
    
  2. เรียกใช้เมธอดจากหน้าเครื่องมือสำหรับนักพัฒนาเว็บโดยใช้ inspectedWindow.eval() พร้อมตัวเลือก useContentScriptContext: true

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

ตัวเลือก useContentScriptContext: true ระบุว่าต้องประเมินนิพจน์ในบริบทเดียวกับ Content Script เพื่อให้เข้าถึงเมธอด setSelectedElement ได้

ดู window ของแผงอ้างอิง

หากต้องการเรียกใช้ postMessage() จากแผง DevTools คุณจะต้องมีการอ้างอิงไปยังออบเจ็กต์ window รับหน้าต่าง iframe ของ แผงจากตัวแฮนเดิลเหตุการณ์ panel.onShown

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

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

โค้ดที่แทรกลงในหน้าเว็บโดยตรงโดยไม่มี Content Script รวมถึงการต่อแท็ก <script> หรือการเรียกใช้ inspectedWindow.eval() จะส่งข้อความไปยังหน้า DevTools โดยใช้ runtime.sendMessage() ไม่ได้ เราขอแนะนำให้ รวมสคริปต์ที่แทรกกับ Content Script ที่ทำหน้าที่เป็นตัวกลาง และใช้ วิธี 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. Note that this is not foolproof
  // and the page can easily spoof messages if it wants to.
  if (typeof message !== 'object' || message === null ||
      message.source !== 'my-devtools-extension') {
    return;
  }

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

ดูเทคนิคการส่งข้อความทางเลือกอื่นๆ ได้ใน GitHub

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

หากต้องการติดตามว่าหน้าต่างเครื่องมือสำหรับนักพัฒนาเว็บเปิดอยู่หรือไม่ ให้เพิ่ม Listener onConnect ลงใน Service Worker แล้วเรียกใช้ 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 service worker
const serviceWorkerConnection = chrome.runtime.connect({
    name: "devtools-page"
});

// Send a periodic heartbeat to keep the port open.
setInterval(() => {
  port.postMessage("heartbeat");
}, 15000);

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

ตัวอย่างในหน้านี้มาจากหน้าต่อไปนี้

  • ส่วนขยาย Polymer Devtools - ใช้ตัวช่วยหลายตัวที่ทำงานในหน้าโฮสต์เพื่อค้นหาสถานะ DOM/JS เพื่อส่งกลับไปยังแผงที่กำหนดเอง
  • ส่วนขยาย React DevTools - ใช้โมดูลย่อยของเครื่องมือแสดงผลเพื่อนำคอมโพเนนต์ UI ของเครื่องมือสำหรับนักพัฒนาเว็บมาใช้ซ้ำ
  • Ember Inspector - แชร์ส่วนขยายหลักกับอแดปเตอร์สำหรับทั้ง Chrome และ Firefox
  • Coquette-inspect - ส่วนขยายที่สะอาดซึ่งอิงตาม React พร้อมด้วยตัวแทนการแก้ไขข้อบกพร่องที่แทรก ลงในหน้าโฮสต์
  • ส่วนขยายตัวอย่างมีส่วนขยายที่คุ้มค่าให้ติดตั้ง ลองใช้ และเรียนรู้เพิ่มเติม

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

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

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

ตัวอย่าง

คุณดูตัวอย่างที่ใช้ API ของเครื่องมือสำหรับนักพัฒนาเว็บได้ในตัวอย่าง