บทแนะนำที่ครอบคลุมแนวคิดเกี่ยวกับโปรแกรมทำงานของบริการส่วนขยาย
ภาพรวม
บทแนะนำนี้จะให้คำแนะนำเกี่ยวกับโปรแกรมทำงานของบริการส่วนขยาย Chrome ในบทแนะนำนี้ คุณจะได้สร้างส่วนขยายที่ช่วยให้ผู้ใช้ไปยังหน้าอ้างอิง API ของ Chrome ได้อย่างรวดเร็วโดยใช้แถบอเนกประสงค์ โดยคุณจะได้เรียนรู้วิธีต่อไปนี้
- ลงทะเบียน Service Worker และนำเข้าโมดูล
- แก้ไขข้อบกพร่องของโปรแกรมทำงานของบริการส่วนขยาย
- จัดการรัฐและจัดการเหตุการณ์
- เรียกเหตุการณ์ตามช่วงเวลา
- สื่อสารกับสคริปต์เนื้อหา
ก่อนจะเริ่ม
คู่มือนี้มีสมมติฐานว่าคุณมีประสบการณ์ในการพัฒนาเว็บขั้นพื้นฐาน เราขอแนะนำให้ดูส่วนขยาย 101 และ Hey World สำหรับข้อมูลเบื้องต้นเกี่ยวกับการพัฒนาส่วนขยาย
สร้างส่วนขยาย
เริ่มด้วยการสร้างไดเรกทอรีใหม่ชื่อ quick-api-reference
เพื่อเก็บไฟล์ส่วนขยาย หรือดาวน์โหลดซอร์สโค้ดจากที่เก็บตัวอย่าง GitHub
ขั้นตอนที่ 1: ลงทะเบียน Service Worker
สร้างไฟล์ไฟล์ Manifest ในรูทของโปรเจ็กต์และเพิ่มโค้ดต่อไปนี้
manifest.json:
{
"manifest_version": 3,
"name": "Open extension API reference",
"version": "1.0.0",
"icons": {
"16": "images/icon-16.png",
"128": "images/icon-128.png"
},
"background": {
"service_worker": "service-worker.js"
}
}
ส่วนขยายจะลงทะเบียน Service Worker ในไฟล์ Manifest ซึ่งต้องใช้ไฟล์ JavaScript เพียงไฟล์เดียวเท่านั้น
ไม่จำเป็นต้องเรียกใช้ navigator.serviceWorker.register()
เหมือนกับในหน้าเว็บ
สร้างโฟลเดอร์ images
จากนั้นดาวน์โหลดไอคอนลงในโฟลเดอร์นั้น
ดูขั้นตอนแรกของบทแนะนำเวลาอ่านเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับข้อมูลเมตาและไอคอนของส่วนขยายในไฟล์ Manifest
ขั้นตอนที่ 2: นำเข้าโมดูล Service Worker หลายรายการ
โปรแกรมทำงานของบริการของเราใช้ฟีเจอร์ 2 อย่าง เราจะนำแต่ละฟีเจอร์ไปใช้ในโมดูลที่แยกกันเพื่อให้บำรุงรักษาได้ดียิ่งขึ้น ก่อนอื่น เราต้องประกาศ Service Worker เป็นโมดูล ES ในไฟล์ Manifest ซึ่งช่วยให้เรานำเข้าโมดูลในโปรแกรมทำงานของบริการได้ ดังนี้
manifest.json:
{
"background": {
"service_worker": "service-worker.js",
"type": "module"
},
}
สร้างไฟล์ service-worker.js
และนำเข้าโมดูล 2 รายการดังนี้
import './sw-omnibox.js';
import './sw-tips.js';
สร้างไฟล์เหล่านี้และเพิ่มบันทึกคอนโซลให้กับแต่ละไฟล์
sw-omnibox.js:
console.log("sw-omnibox.js");
sw-tips.js:
console.log("sw-tips.js");
ดูการนำเข้าสคริปต์เพื่อดูวิธีอื่นๆ ในการนำเข้าไฟล์หลายไฟล์ในโปรแกรมทำงานของบริการ
ไม่บังคับ: การแก้ไขข้อบกพร่อง Service Worker
เราจะอธิบายวิธีค้นหาบันทึกของ Service Worker และทราบว่าหยุดทำงานเมื่อใด ก่อนอื่นให้ทำตามวิธีการโหลดส่วนขยายที่คลายการแพคแล้ว
หลังจาก 30 วินาที คุณจะเห็น "Service Worker (ไม่ใช้งาน)" ซึ่งหมายความว่าโปรแกรมทำงานของบริการได้สิ้นสุดลงแล้ว คลิกลิงก์ "Service Worker (ไม่ใช้งาน)" เพื่อตรวจสอบ ภาพเคลื่อนไหวต่อไปนี้จะแสดง
คุณสังเกตเห็นว่าการตรวจสอบโปรแกรมทำงานของบริการช่วยปลุกระบบให้ทำงานหรือไม่ การเปิด Service Worker ในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์จะทำให้มันทำงานต่อไป อย่าลืมปิดเครื่องมือสำหรับนักพัฒนาเว็บเพื่อให้ส่วนขยายทำงานได้อย่างถูกต้องเมื่อสิ้นสุดการให้บริการ
ตอนนี้ให้แยกส่วนขยายเพื่อดูว่าจะหาข้อผิดพลาดได้จากที่ใด วิธีหนึ่งคือการลบ ".js" ออกจากการนำเข้า './sw-omnibox.js'
ในไฟล์ service-worker.js
Chrome จะลงทะเบียน Service Worker ไม่ได้
กลับไปที่ chrome://extensions แล้วรีเฟรชส่วนขยาย คุณจะเห็นข้อผิดพลาด 2 อย่างดังนี้
Service worker registration failed. Status code: 3.
An unknown error occurred when fetching the script.
โปรดดูวิธีอื่นๆ ในการแก้ไขข้อบกพร่องของโปรแกรมทำงานของบริการส่วนขยายได้ที่การแก้ไขข้อบกพร่องของส่วนขยาย
ขั้นตอนที่ 4: เริ่มต้นสถานะ
Chrome จะปิดโปรแกรมทำงานของบริการหากไม่จำเป็น เราใช้ API ของ chrome.storage
เพื่อคงสถานะไว้ในเซสชันของ Service Worker สำหรับการเข้าถึงพื้นที่เก็บข้อมูล เราจำเป็นต้องขอสิทธิ์ในไฟล์ Manifest
manifest.json:
{
...
"permissions": ["storage"],
}
ขั้นแรก ให้บันทึกคำแนะนำเริ่มต้นลงในพื้นที่เก็บข้อมูล เราเริ่มสถานะเมื่อมีการติดตั้งส่วนขยายเป็นครั้งแรกได้โดยฟังเหตุการณ์ runtime.onInstalled()
ดังนี้
sw-omnibox.js:
...
// Save default API suggestions
chrome.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'install') {
chrome.storage.local.set({
apiSuggestions: ['tabs', 'storage', 'scripting']
});
}
});
Service Worker ไม่มีสิทธิ์เข้าถึงออบเจ็กต์หน้าต่างโดยตรง ดังนั้นจึงใช้ window.localStorage
เพื่อจัดเก็บค่าไม่ได้ นอกจากนี้ โปรแกรมทำงานของบริการยังเป็นสภาพแวดล้อมการดำเนินการที่มีระยะเวลาสั้น โดยระบบจะสิ้นสุดการทำงานซ้ำๆ ตลอดเซสชันเบราว์เซอร์ของผู้ใช้ ซึ่งทำให้โปรแกรมทำงานบนตัวแปรร่วมไม่ได้ แต่ให้ใช้ chrome.storage.local
ซึ่งจัดเก็บข้อมูลไว้ในเครื่องแทน
โปรดดูหัวข้อคงข้อมูลไว้แทนที่จะใช้ตัวแปรร่วมเพื่อดูข้อมูลเกี่ยวกับตัวเลือกพื้นที่เก็บข้อมูลอื่นๆ สำหรับผู้ปฏิบัติงานของบริการส่วนขยาย
ขั้นตอนที่ 5: บันทึกกิจกรรม
Listener เหตุการณ์ทั้งหมดจะต้องลงทะเบียนแบบคงที่ในขอบเขตรวมของ Service Worker กล่าวคือ Listener เหตุการณ์ไม่ควรฝังอยู่ในฟังก์ชันที่ไม่พร้อมกัน ซึ่งจะช่วยให้ Chrome มั่นใจได้ว่าตัวแฮนเดิลเหตุการณ์ทั้งหมดจะได้รับการคืนค่าในกรณีที่เริ่มการทำงานของ Service Worker
ในตัวอย่างนี้ เราจะใช้ API ของ chrome.omnibox
แต่ก่อนอื่นเราต้องประกาศทริกเกอร์คีย์เวิร์ดของแถบอเนกประสงค์ในไฟล์ Manifest ดังนี้
manifest.json:
{
...
"minimum_chrome_version": "102",
"omnibox": {
"keyword": "api"
},
}
ตอนนี้ ให้ลงทะเบียน Listener เหตุการณ์ของแถบอเนกประสงค์ที่สคริปต์ระดับบนสุด เมื่อผู้ใช้ป้อนคีย์เวิร์ดในแถบอเนกประสงค์ (api
) ในแถบที่อยู่ตามด้วยแท็บหรือพื้นที่ทำงาน Chrome จะแสดงรายการคำแนะนำตามคีย์เวิร์ดในพื้นที่เก็บข้อมูล เหตุการณ์ onInputChanged()
ซึ่งป้อนข้อมูลของผู้ใช้ปัจจุบันและออบเจ็กต์ suggestResult
มีหน้าที่ป้อนข้อมูลคำแนะนำเหล่านี้
sw-omnibox.js:
...
const URL_CHROME_EXTENSIONS_DOC =
'https://developer.chrome.com/docs/extensions/reference/';
const NUMBER_OF_PREVIOUS_SEARCHES = 4;
// Display the suggestions after user starts typing
chrome.omnibox.onInputChanged.addListener(async (input, suggest) => {
await chrome.omnibox.setDefaultSuggestion({
description: 'Enter a Chrome API or choose from past searches'
});
const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
const suggestions = apiSuggestions.map((api) => {
return { content: api, description: `Open chrome.${api} API` };
});
suggest(suggestions);
});
หลังจากที่ผู้ใช้เลือกคำแนะนำแล้ว onInputEntered()
จะเปิดหน้าข้อมูลอ้างอิงของ Chrome API ที่เกี่ยวข้อง
sw-omnibox.js:
...
// Open the reference page of the chosen API
chrome.omnibox.onInputEntered.addListener((input) => {
chrome.tabs.create({ url: URL_CHROME_EXTENSIONS_DOC + input });
// Save the latest keyword
updateHistory(input);
});
ฟังก์ชัน updateHistory()
จะรับการป้อนข้อมูลในแถบอเนกประสงค์และบันทึกไว้ใน storage.local
วิธีนี้จะทำให้ระบบใช้ข้อความค้นหาล่าสุดเป็นคำแนะนำของแถบอเนกประสงค์ได้ในภายหลัง
sw-omnibox.js:
...
async function updateHistory(input) {
const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
apiSuggestions.unshift(input);
apiSuggestions.splice(NUMBER_OF_PREVIOUS_SEARCHES);
return chrome.storage.local.set({ apiSuggestions });
}
ขั้นตอนที่ 6: ตั้งค่ากิจกรรมที่เกิดซ้ำ
เมธอด setTimeout()
หรือ setInterval()
มักใช้เพื่อทำงานที่ล่าช้าหรือเป็นระยะๆ อย่างไรก็ตาม API เหล่านี้อาจล้มเหลวเนื่องจากเครื่องจัดตารางเวลาจะยกเลิกตัวจับเวลาเมื่อโปรแกรมทำงานของบริการสิ้นสุดลง แต่ส่วนขยายจะใช้ API ของ chrome.alarms
แทนได้
เริ่มต้นด้วยการขอสิทธิ์ "alarms"
ในไฟล์ Manifest นอกจากนี้ หากต้องการดึงข้อมูลเคล็ดลับส่วนขยายจากตำแหน่งที่โฮสต์ระยะไกล คุณต้องขอสิทธิ์โฮสต์ โดยทำดังนี้
manifest.json:
{
...
"permissions": ["storage"],
"permissions": ["storage", "alarms"],
"host_permissions": ["https://extension-tips.glitch.me/*"],
}
ส่วนขยายจะดึงข้อมูลเคล็ดลับทั้งหมดขึ้นมาแบบสุ่มเลือก 1 รายการและบันทึกลงในพื้นที่เก็บข้อมูล เราจะสร้างการปลุกที่จะเรียกใช้วันละครั้งเพื่ออัปเดตเคล็ดลับ ระบบจะไม่บันทึกการปลุกเมื่อคุณปิด Chrome เราจึงต้องตรวจสอบว่ามีการปลุกนั้นหรือไม่ และสร้างหากยังไม่มี
sw-tips.js:
// Fetch tip & save in storage
const updateTip = async () => {
const response = await fetch('https://extension-tips.glitch.me/tips.json');
const tips = await response.json();
const randomIndex = Math.floor(Math.random() * tips.length);
return chrome.storage.local.set({ tip: tips[randomIndex] });
};
const ALARM_NAME = 'tip';
// Check if alarm exists to avoid resetting the timer.
// The alarm might be removed when the browser session restarts.
async function createAlarm() {
const alarm = await chrome.alarms.get(ALARM_NAME);
if (typeof alarm === 'undefined') {
chrome.alarms.create(ALARM_NAME, {
delayInMinutes: 1,
periodInMinutes: 1440
});
updateTip();
}
}
createAlarm();
// Update tip once a day
chrome.alarms.onAlarm.addListener(updateTip);
ขั้นตอนที่ 7: สื่อสารกับบริบทอื่นๆ
ส่วนขยายใช้สคริปต์เนื้อหาเพื่ออ่านและแก้ไขเนื้อหาของหน้าเว็บ เมื่อผู้ใช้เข้าชมหน้าอ้างอิง API ของ Chrome สคริปต์เนื้อหาของส่วนขยายจะอัปเดตหน้าด้วยเคล็ดลับประจำวัน การดำเนินการนี้จะส่งข้อความเพื่อขอทิปของวันจาก Service Worker
เริ่มต้นด้วยการประกาศสคริปต์เนื้อหาในไฟล์ Manifest และเพิ่มรูปแบบการจับคู่ที่สอดคล้องกับเอกสารอ้างอิงของ Chrome API
manifest.json:
{
...
"content_scripts": [
{
"matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
"js": ["content.js"]
}
]
}
สร้างไฟล์เนื้อหาใหม่ รหัสต่อไปนี้จะส่งข้อความถึงโปรแกรมทำงานของบริการเพื่อขอเคล็ดลับ จากนั้นเพิ่มปุ่มที่จะเปิดป๊อปอัปที่มีเคล็ดลับสำหรับส่วนขยาย โค้ดนี้ใช้แพลตฟอร์มเว็บใหม่ Popover API
content.js:
(async () => {
// Sends a message to the service worker and receives a tip in response
const { tip } = await chrome.runtime.sendMessage({ greeting: 'tip' });
const nav = document.querySelector('.upper-tabs > nav');
const tipWidget = createDomElement(`
<button type="button" popovertarget="tip-popover" popovertargetaction="show" style="padding: 0 12px; height: 36px;">
<span style="display: block; font: var(--devsite-link-font,500 14px/20px var(--devsite-primary-font-family));">Tip</span>
</button>
`);
const popover = createDomElement(
`<div id='tip-popover' popover style="margin: auto;">${tip}</div>`
);
document.body.append(popover);
nav.append(tipWidget);
})();
function createDomElement(html) {
const dom = new DOMParser().parseFromString(html, 'text/html');
return dom.body.firstElementChild;
}
ขั้นตอนสุดท้ายคือการเพิ่มเครื่องจัดการข้อความลงใน Service Worker ที่ส่งการตอบกลับสคริปต์เนื้อหาพร้อมเคล็ดลับประจำวัน
sw-tips.js:
...
// Send tip to content script via messaging
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.greeting === 'tip') {
chrome.storage.local.get('tip').then(sendResponse);
return true;
}
});
ทดสอบว่าใช้งานได้
ตรวจสอบว่าโครงสร้างไฟล์ของโปรเจ็กต์มีลักษณะดังนี้
โหลดส่วนขยายในเครื่อง
หากต้องการโหลดส่วนขยายที่คลายการแพคแล้วในโหมดนักพัฒนาซอฟต์แวร์ ให้ทำตามขั้นตอนใน Hello world
เปิดหน้าข้อมูลอ้างอิง
- ป้อนคีย์เวิร์ด "api" ในแถบที่อยู่ของเบราว์เซอร์
- กด "Tab" หรือ "Space"
- ป้อนชื่อเต็มของ API
- หรือเลือกจากรายการการค้นหาที่ผ่านมา
- หน้าใหม่จะเปิดหน้าข้อมูลอ้างอิง API ของ Chrome
ซึ่งควรมีลักษณะดังนี้
![การอ้างอิง API ด่วน เปิดการอ้างอิง API รันไทม์](https://developer.chrome.google.cn/static/docs/extensions/get-started/tutorial/service-worker-events/image/quick-api-reference-openi-5041b3b640769.gif?authuser=6&hl=th)
เปิดเคล็ดลับประจำวัน
คลิกปุ่ม เคล็ดลับ บนแถบนำทางเพื่อเปิดเคล็ดลับส่วนขยาย
![เปิดเคล็ดลับประจำวันใน](https://developer.chrome.google.cn/static/docs/extensions/get-started/tutorial/service-worker-events/image/open-daily-tip-676249a78de8e.gif?authuser=6&hl=th)
🎯 การเพิ่มประสิทธิภาพที่เป็นไปได้
จากสิ่งที่คุณได้เรียนรู้ในวันนี้ ลองทำอย่างใดอย่างหนึ่งต่อไปนี้:
- สำรวจอีกวิธีหนึ่งในการนำคำแนะนำของแถบอเนกประสงค์ไปใช้
- สร้างโมดัลที่กำหนดเองสำหรับแสดงเคล็ดลับส่วนขยาย
- เปิดหน้าเพิ่มเติมเพื่อไปยังหน้า API อ้างอิงส่วนขยายเว็บของ MDN
สร้างชุมชนให้เติบโตไปเรื่อยๆ
ขอแสดงความยินดีที่จบบทแนะนำนี้ 🎉 เพิ่มระดับทักษะต่อไปโดยเรียนรู้บทแนะนำอื่นๆ สำหรับมือใหม่:
ส่วนขยาย | สิ่งที่คุณจะได้เรียนรู้ |
---|---|
เวลาในการอ่าน | แทรกองค์ประกอบในชุดหน้าเว็บที่ต้องการโดยอัตโนมัติ |
เครื่องมือจัดการแท็บ | เพื่อสร้างป๊อปอัปที่จัดการแท็บของเบราว์เซอร์ |
โหมดโฟกัส | เพื่อเรียกใช้โค้ดในหน้าปัจจุบันหลังจากคลิกการทำงานของส่วนขยาย |
สำรวจต่อ
เราขอแนะนำให้อ่านบทความต่อไปนี้เพื่อศึกษาเส้นทางการเรียนรู้ของโปรแกรมทำงานของบริการส่วนขยายต่อ