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

สคริปต์เนื้อหาเป็นไฟล์ที่ทำงานในบริบทของหน้าเว็บ การใช้เอกสารมาตรฐาน Object Model (DOM) เพื่อให้อ่านรายละเอียด ของหน้าเว็บที่เบราว์เซอร์เข้าชมได้ เปลี่ยนแปลง และส่งข้อมูลไปยังส่วนขยายหลัก

ทำความเข้าใจความสามารถของสคริปต์เนื้อหา

สคริปต์เนื้อหาสามารถเข้าถึง API ของส่วนขยายต่อไปนี้ได้โดยตรง

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

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

ทำงานในโลกที่โดดเดี่ยว

สคริปต์เนื้อหาทำงานอยู่ในโลกที่โดดเดี่ยว ทำให้สคริปต์เนื้อหาสามารถทำการเปลี่ยนแปลง สภาพแวดล้อม JavaScript ที่ไม่ขัดแย้งกับหน้าเว็บหรือส่วนขยายอื่นๆ สคริปต์เนื้อหา

ส่วนขยายอาจทำงานในหน้าเว็บที่มีโค้ดคล้ายกับตัวอย่างต่อไปนี้

webPage.html

<html>
  <button id="mybutton">click me</button>
  <script>
    var greeting = "hello, ";
    var button = document.getElementById("mybutton");
    button.person_name = "Bob";
    button.addEventListener(
        "click", () => alert(greeting + button.person_name + "."), false);
  </script>
</html>

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

content-script.js

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener(
    "click", () => alert(greeting + button.person_name + "."), false);

การเปลี่ยนแปลงนี้จะทำให้การแจ้งเตือนทั้งสองแสดงตามลำดับเมื่อคลิกปุ่ม

แทรกสคริปต์

สคริปต์เนื้อหาสามารถประกาศแบบคงที่ ประกาศ แบบไดนามิกหรือการแทรกแบบเป็นโปรแกรม

แทรกการประกาศแบบคงที่

ใช้การประกาศสคริปต์เนื้อหาแบบคงที่ในไฟล์ Manifest.json สำหรับสคริปต์ที่ระบบควรเรียกใช้โดยอัตโนมัติ แสดงในชุดของหน้าเว็บที่รู้จักกันดี

สคริปต์ที่ประกาศแบบคงที่จะมีการลงทะเบียนในไฟล์ Manifest ภายใต้คีย์ "content_scripts" โดยจะรวมไฟล์ JavaScript, ไฟล์ CSS หรือทั้ง 2 อย่างก็ได้ สคริปต์เนื้อหาที่เรียกใช้อัตโนมัติทั้งหมดต้องระบุ รูปแบบที่ตรงกัน

manifest.json

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["https://*.nytimes.com/*"],
     "css": ["my-styles.css"],
     "js": ["content-script.js"]
   }
 ],
 ...
}

ชื่อ ประเภท คำอธิบาย
matches อาร์เรย์ของสตริง ต้องระบุ ระบุหน้าที่จะแทรกสคริปต์เนื้อหานี้ ดูรูปแบบการจับคู่สำหรับรายละเอียดเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ และจับคู่รูปแบบและ globs สำหรับข้อมูลเกี่ยวกับวิธียกเว้น URL
css อาร์เรย์ของสตริง ไม่บังคับ รายการไฟล์ CSS ที่จะแทรกลงในหน้าที่ตรงกัน สิ่งเหล่านี้คือ แทรกตามลำดับที่ปรากฏในอาร์เรย์นี้ ก่อนที่จะมีการสร้างหรือแสดง DOM สำหรับหน้านั้น
js อาร์เรย์ของสตริง ไม่บังคับ รายการไฟล์ JavaScript ที่จะแทรกลงในหน้าที่ตรงกัน ไฟล์ จะถูกแทรกตามลำดับที่ปรากฏในอาร์เรย์นี้ แต่ละสตริงในรายการนี้ต้องมี เส้นทางแบบสัมพัทธ์ไปยังทรัพยากรในไดเรกทอรีรากของส่วนขยาย เครื่องหมายทับ ("/") คือ จะตัดโดยอัตโนมัติ
run_at RunAt ไม่บังคับ ระบุเวลาที่ควรแทรกสคริปต์ลงในหน้าเว็บ ค่าเริ่มต้นคือ document_idle
match_about_blank boolean ไม่บังคับ สคริปต์ควรแทรกลงในเฟรม about:blank หรือไม่ โดยที่เฟรมระดับบนสุดหรือเฟรมแบบเปิดตรงกับรูปแบบที่ประกาศไว้ใน matches ค่าเริ่มต้นคือ "เท็จ"
match_origin_as_fallback boolean ไม่บังคับ สคริปต์ควรแทรกในเฟรมที่ สร้างโดยต้นทางที่ตรงกัน แต่ URL หรือต้นทางอาจไม่ได้เชื่อมโดยตรง จับคู่รูปแบบ ซึ่งรวมถึงเฟรมที่มีรูปแบบแตกต่างกัน เช่น about:, data:, blob: และ filesystem: ดูเพิ่มเติม การแทรกในเฟรมที่เกี่ยวข้อง
world ExecutionWorld ไม่บังคับ โลก JavaScript ที่สคริปต์จะทำงานภายใน ค่าเริ่มต้นคือ ISOLATED ดูเพิ่มเติม ทำงานในโลกที่โดดเดี่ยว

แทรกด้วยการประกาศแบบไดนามิก

สคริปต์เนื้อหาแบบไดนามิกมีประโยชน์เมื่อรูปแบบการจับคู่สำหรับสคริปต์เนื้อหา ไม่ค่อยเป็นที่รู้จัก หรือเมื่อไม่มีการแทรกสคริปต์เนื้อหาบนโฮสต์ที่รู้จักเสมอไป

ซึ่งใน Chrome 96 นั้น การประกาศแบบไดนามิกนั้นคล้ายกับแบบคงที่ ของคุณ แต่ออบเจ็กต์สคริปต์เนื้อหามีการลงทะเบียนกับ Chrome โดยใช้ ใน เนมสเปซ chrome.scripting ไม่ใช่ใน manifest.json. นอกจากนี้ Scripting API ยังทำให้นักพัฒนาส่วนขยาย เป็น:

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

การประกาศแบบไดนามิกอาจรวมไฟล์ JavaScript, ไฟล์ CSS หรือทั้ง 2 อย่าง เช่นเดียวกับการประกาศแบบคงที่

service-worker.js

chrome.scripting
  .registerContentScripts([{
    id: "session-script",
    js: ["content.js"],
    persistAcrossSessions: false,
    matches: ["*://example.com/*"],
    runAt: "document_start",
  }])
  .then(() => console.log("registration complete"))
  .catch((err) => console.warn("unexpected error", err))

service-worker.js

chrome.scripting
  .updateContentScripts([{
    id: "session-script",
    excludeMatches: ["*://admin.example.com/*"],
  }])
  .then(() => console.log("registration updated"));

service-worker.js

chrome.scripting
  .getRegisteredContentScripts()
  .then(scripts => console.log("registered content scripts", scripts));

service-worker.js

chrome.scripting
  .unregisterContentScripts({ ids: ["session-script"] })
  .then(() => console.log("un-registration complete"));

แทรกแบบเป็นโปรแกรม

ใช้การแทรกแบบเป็นโปรแกรมสำหรับสคริปต์เนื้อหาที่ต้องทำงานเพื่อตอบสนองต่อเหตุการณ์หรือ โอกาส

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

ต่อไปนี้เป็นเวอร์ชันต่างๆ ของส่วนขยายที่ใช้แท็บแอ็กทีฟ

manifest.json:

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Action Button"
  }
}

สคริปต์เนื้อหาสามารถแทรกเป็นไฟล์

content-script.js


document.body.style.backgroundColor = "orange";

service-worker.js

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ["content-script.js"]
  });
});

หรือจะแทรกและใช้เนื้อหาของฟังก์ชันเป็นสคริปต์เนื้อหาก็ได้

service-worker.js

function injectedFunction() {
  document.body.style.backgroundColor = "orange";
}

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target : {tabId : tab.id},
    func : injectedFunction,
  });
});

โปรดทราบว่าฟังก์ชันที่แทรกเป็นสำเนาของฟังก์ชันที่อ้างอิงใน การเรียกใช้ chrome.scripting.executeScript() ไม่ใช่ฟังก์ชันต้นฉบับ ดังนั้น ฟังก์ชัน ร่างกายต้องควบคุมตัวเองได้ การอ้างอิงไปยังตัวแปรนอกฟังก์ชันจะทำให้เนื้อหา เพื่อส่ง ReferenceError

เมื่อแทรกเป็นฟังก์ชัน คุณจะส่งอาร์กิวเมนต์ไปยังฟังก์ชันได้ด้วย

service-worker.js

function injectedFunction(color) {
  document.body.style.backgroundColor = color;
}

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target : {tabId : tab.id},
    func : injectedFunction,
    args : [ "orange" ],
  });
});

ไม่รวมการแข่งขันและ glob

หากต้องการปรับแต่งการจับคู่หน้าที่ระบุ ให้ใส่ฟิลด์ต่อไปนี้ในการประกาศ การลงทะเบียน

ชื่อ ประเภท คำอธิบาย
exclude_matches อาร์เรย์ของสตริง ไม่บังคับ ยกเว้นหน้าที่มีการแทรกสคริปต์เนื้อหานี้ เข้าไปด้วย โปรดดูที่รูปแบบการจับคู่สำหรับรายละเอียดเกี่ยวกับไวยากรณ์ของ สตริงเหล่านี้
include_globs อาร์เรย์ของสตริง ไม่บังคับ ใช้หลังวันที่ matches เพื่อรวมเฉพาะ URL ที่ ตรงกับโลกนี้ ส่วนนี้มีไว้เพื่อจำลอง @include คีย์เวิร์ด Greasemonkey
exclude_globs อาร์เรย์ของสตริง ไม่บังคับ ใช้หลังวันที่ matches เพื่อยกเว้น URL ที่ตรงกับรายการนี้ glob ตั้งใจที่จะจำลอง@exclude คีย์เวิร์ด Greasemonkey

ระบบจะแทรกสคริปต์เนื้อหาลงในหน้าเว็บหากเงื่อนไขทั้ง 2 ข้อต่อไปนี้เป็นจริง

  • URL ของ URL ตรงกับรูปแบบ matches และรูปแบบ include_globs ใดก็ได้
  • URL ไม่ตรงกับรูปแบบ exclude_matches หรือ exclude_globs ด้วย เนื่องจากจำเป็นต้องมีพร็อพเพอร์ตี้ matches, exclude_matches, include_globs และ exclude_globs สามารถใช้ในการจำกัดหน้าเว็บที่จะได้รับผลกระทบเท่านั้น

ส่วนขยายต่อไปนี้แทรกสคริปต์เนื้อหาลงใน https://www.nytimes.com/health แต่ไม่อยู่ใน https://www.nytimes.com/business

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

service-worker.js

chrome.scripting.registerContentScripts([{
  id : "test",
  matches : [ "https://*.nytimes.com/*" ],
  excludeMatches : [ "*://*/*business*" ],
  js : [ "contentScript.js" ],
}]);

พร็อพเพอร์ตี้ Glob มีไวยากรณ์ที่ยืดหยุ่นและแตกต่างจากรูปแบบการจับคู่ glob ที่ยอมรับ สตริงคือ URL ที่อาจมี "ไวลด์การ์ด" เครื่องหมายดอกจันและเครื่องหมายคำถาม เครื่องหมายดอกจัน (*) จะจับคู่สตริงใดก็ได้ที่มีความยาว รวมทั้งสตริงว่าง ขณะที่เครื่องหมายคำถาม (?) จะจับคู่ อักขระเดี่ยวๆ

ตัวอย่างเช่น glob https://???.example.com/foo/\* ตรงกับรายการใดรายการหนึ่งต่อไปนี้

  • https://www.example.com/foo/bar
  • https://the.example.com/foo/

แต่จะไม่ตรงกับเงื่อนไขต่อไปนี้

  • https://my.example.com/foo/bar
  • https://example.com/foo/
  • https://www.example.com/foo

ส่วนขยายนี้แทรกสคริปต์เนื้อหาลงใน https://www.nytimes.com/arts/index.html และ https://www.nytimes.com/jobs/index.htm* แต่ไม่เข้าไปใน https://www.nytimes.com/sports/index.html:

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

ส่วนขยายนี้แทรกสคริปต์เนื้อหาลงใน https://history.nytimes.com และ https://.nytimes.com/history แต่ไม่เข้าไปใน https://science.nytimes.com หรือ https://www.nytimes.com/science:

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

คุณใส่อุปกรณ์เหล่านี้ ทั้งหมด หรือบางส่วนได้เพื่อให้กำหนดขอบเขตที่ถูกต้อง

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

เวลาทำงาน

ช่อง run_at จะควบคุมเมื่อมีการแทรกไฟล์ JavaScript ลงในหน้าเว็บ รูปแบบที่แนะนำและ ค่าเริ่มต้นคือ "document_idle" ดูประเภท RunAt เพื่อหาข้อผิดพลาดอื่นๆ

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}

service-worker.js

chrome.scripting.registerContentScripts([{
  id : "test",
  matches : [ "https://*.nytimes.com/*" ],
  runAt : "document_idle",
  js : [ "contentScript.js" ],
}]);
ชื่อ ประเภท คำอธิบาย
document_idle สตริง แนะนำ ใช้ "document_idle" เมื่อใดก็ตามที่เป็นไปได้

เบราว์เซอร์ เลือกเวลาที่จะแทรกสคริปต์ระหว่าง "document_end" และทันทีหลังจากโดยทันที window.onload เริ่มทำงาน ช่วงเวลาที่แน่นอนของการแทรกจะขึ้นอยู่กับความซับซ้อนของเอกสารและ ใช้เวลาโหลดนาน และได้รับการปรับให้เหมาะกับความเร็วในการโหลดหน้าเว็บ

สคริปต์เนื้อหา ซึ่งทำงานที่ "document_idle" ไม่จำเป็นต้องคอยฟัง window.onload เป็นการรับประกันได้ว่าจะทำงานหลังจาก DOM เสร็จสมบูรณ์ หากมี จะต้องทำงานหลัง window.onload อย่างแน่นอน ส่วนขยายนี้จะตรวจสอบว่า onload ได้เริ่มทำงานแล้วโดยใช้ document.readyState
document_start สตริง ระบบจะแทรกสคริปต์หลังไฟล์ต่างๆ จาก css แต่อยู่ก่อน DOM อื่นๆ สร้างขึ้นหรือเรียกใช้สคริปต์อื่นๆ
document_end สตริง ระบบจะแทรกสคริปต์ทันทีหลังจาก DOM เสร็จสมบูรณ์ แต่ก่อนทรัพยากรย่อย เช่น โหลดรูปภาพและเฟรมแล้ว

ระบุเฟรม

ช่อง "all_frames" ช่วยให้ส่วนขยายระบุได้ว่าควรแนบไฟล์ JavaScript และ CSS หรือไม่ แทรกลงในเฟรมทั้งหมดที่ตรงกับข้อกำหนดของ URL ที่ระบุ หรือเฉพาะในเฟรมระดับบนสุดใน

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}

service-worker.js

chrome.scripting.registerContentScripts([{
  id: "test",
  matches : [ "https://*.nytimes.com/*" ],
  allFrames : true,
  js : [ "contentScript.js" ],
}]);
ชื่อ ประเภท คำอธิบาย
all_frames boolean ไม่บังคับ ค่าเริ่มต้นคือ false ซึ่งหมายความว่าเฉพาะเฟรมด้านบนเท่านั้น ตรงกัน

หากระบุ true ไว้ ระบบจะแทรกเฟรมทั้งหมดลงใน เฟรมไม่ใช่เฟรมบนสุดในแท็บ ระบบจะตรวจสอบ URL แต่ละเฟรมแยกกัน โดยจะไม่แทรกลงในเฟรมย่อยหากไม่เป็นไปตามข้อกำหนดของ URL

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

ในกรณีที่ส่วนขยายต้องการแทรก URL ในเฟรม มี about:, data:, blob: และ filesystem: ในกรณีเหล่านี้ พารามิเตอร์ URL จะไม่ตรงกับรูปแบบของสคริปต์เนื้อหา (และในกรณีของ about: และ data: ไม่ต้องรวม URL หลักหรือต้นทางไว้ใน URL เลย เช่น about:blank หรือ data:text/html,<html>Hello, World!</html>) อย่างไรก็ตาม เฟรมเหล่านี้ยังคงสามารถเชื่อมโยงกับเฟรมที่สร้างได้

ในการแทรกลงในเฟรมเหล่านี้ ส่วนขยายสามารถระบุ "match_origin_as_fallback" ในข้อกำหนดของสคริปต์เนื้อหาในคุณสมบัติ ไฟล์ Manifest

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.google.com/*"],
      "match_origin_as_fallback": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}

เมื่อระบุและตั้งค่าเป็น true แล้ว Chrome จะดูต้นทางของ ที่เป็นตัวเริ่ม ของเฟรมเพื่อพิจารณาว่าเฟรมตรงกันหรือไม่ แทนที่จะเป็น URL ของเฟรมเอง โปรดทราบว่านี่อาจแตกต่างจาก ต้นทางของเฟรมเป้าหมาย (เช่น URL data: รายการมีต้นทางเป็น Null)

จุดเริ่มของเฟรมคือเฟรมที่สร้างหรือนำทางเป้าหมาย เฟรม แม้ว่าโดยทั่วไปจะเป็นรายการระดับบนโดยตรงหรือเงื่อนไขเริ่มต้น แต่ก็อาจไม่ใช่ (เช่น ในกรณีที่เฟรมนำทาง iframe ภายใน iframe)

เนื่องจากจะเป็นการเปรียบเทียบต้นทางของเฟรมของผู้เริ่ม เฟรมของผู้เริ่ม อาจอยู่ที่เส้นทางใดก็ได้จากต้นกำเนิดนั้น เพื่ออธิบายนัยนี้ให้ชัดเจน Chrome ต้องมีสคริปต์เนื้อหาที่ระบุด้วย "match_origin_as_fallback" ตั้งค่าเป็น true เพื่อระบุเส้นทางของ * ด้วย

เมื่อระบุทั้ง "match_origin_as_fallback" และ "match_about_blank" แล้ว "match_origin_as_fallback" มีลำดับความสำคัญสูงสุด

การสื่อสารกับหน้าเว็บที่ฝัง

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

ตัวอย่างสามารถทำได้โดยใช้ window.postMessage()

content-script.js

var port = chrome.runtime.connect();

window.addEventListener("message", (event) => {
  // We only accept messages from ourselves
  if (event.source !== window) {
    return;
  }

  if (event.data.type && (event.data.type === "FROM_PAGE")) {
    console.log("Content script received: " + event.data.text);
    port.postMessage(event.data.text);
  }
}, false);

example.js

document.getElementById("theButton").addEventListener("click", () => {
  window.postMessage(
      {type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);

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

เข้าถึงไฟล์ส่วนขยาย

หากต้องการเข้าถึงไฟล์ส่วนขยายจากสคริปต์เนื้อหา คุณสามารถเรียกใช้ chrome.runtime.getURL() เพื่อรับ URL ที่สมบูรณ์ของชิ้นงานส่วนขยายตามที่แสดงในตัวอย่างต่อไปนี้ (content.js)

content-script.js

let image = chrome.runtime.getURL("images/my_image.png")

หากต้องการใช้แบบอักษรหรือรูปภาพในไฟล์ CSS คุณสามารถใช้ @@extension_id เพื่อสร้าง URL ตามที่แสดงในตัวอย่างต่อไปนี้ (content.css)

content.css

body {
 background-image:url('chrome-extension://__MSG_@@extension_id__/background.png');
}

@font-face {
 font-family: 'Stint Ultra Expanded';
 font-style: normal;
 font-weight: 400;
 src: url('chrome-extension://__MSG_@@extension_id__/fonts/Stint Ultra Expanded.woff') format('woff');
}

เนื้อหาทั้งหมดต้องประกาศเป็นทรัพยากรที่เข้าถึงได้ทางเว็บในไฟล์ manifest.json ดังนี้

manifest.json

{
 ...
 "web_accessible_resources": [
   {
     "resources": [ "images/*.png" ],
     "matches": [ "https://example.com/*" ]
   },
   {
     "resources": [ "fonts/*.woff" ],
     "matches": [ "https://example.com/*" ]
   }
 ],
 ...
}

ปลอดภัยอยู่เสมอ

แม้ว่าโลกที่โดดเดี่ยวจะให้การปกป้องอีกชั้นหนึ่ง แต่การใช้สคริปต์เนื้อหาสามารถสร้าง ช่องโหว่ในส่วนขยายและหน้าเว็บ หากสคริปต์เนื้อหาได้รับเนื้อหาจาก เว็บไซต์แยกต่างหาก เช่น การเรียก fetch() โปรดระมัดระวังเพื่อกรองเนื้อหา การโจมตี cross-site Scripting ก่อนแทรกสคริปต์ สื่อสารผ่าน HTTPS เท่านั้นเพื่อ หลีกเลี่ยงการโจมตีแบบ &quot;man-in-the-middle&quot;

และอย่าลืมกรองหน้าเว็บที่เป็นอันตราย ตัวอย่างเช่น รูปแบบต่อไปนี้เป็นอันตราย และ ไม่อนุญาตในไฟล์ Manifest V3:

ไม่ควรทำ

content-script.js

const data = document.getElementById("json-data");
// WARNING! Might be evaluating an evil script!
const parsed = eval("(" + data + ")");
ไม่ควรทำ

content-script.js

const elmt_id = ...
// WARNING! elmt_id might be '); ... evil script ... //'!
window.setTimeout("animate(" + elmt_id + ")", 200);

แต่ให้ใช้ API ที่ปลอดภัยกว่าซึ่งไม่เรียกใช้สคริปต์แทน ดังนี้

ควรทำ

content-script.js

const data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
const parsed = JSON.parse(data);
ควรทำ

content-script.js

const elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(() => animate(elmt_id), 200);