บทแนะนำที่ครอบคลุมแนวคิดของ Service Worker ส่วนขยาย
ภาพรวม
บทแนะนำนี้จะให้ข้อมูลเบื้องต้นเกี่ยวกับโปรแกรมทำงานของบริการส่วนขยายของ Chrome ส่วนหนึ่งของการเปลี่ยนแปลงนี้ คุณจะสร้างส่วนขยายที่ช่วยให้ผู้ใช้ไปยังข้อมูลอ้างอิงของ Chrome API ได้อย่างรวดเร็ว หน้าเว็บที่ใช้แถบอเนกประสงค์ โดยคุณจะได้เรียนรู้วิธีต่อไปนี้
- ลงทะเบียน Service Worker และนำเข้าโมดูล
- แก้ไขข้อบกพร่องโปรแกรมทำงานของบริการส่วนขยาย
- จัดการสถานะและจัดการเหตุการณ์
- ทริกเกอร์เหตุการณ์เป็นระยะๆ
- สื่อสารกับสคริปต์เนื้อหา
ก่อนจะเริ่ม
คู่มือนี้จะถือว่าคุณมีประสบการณ์พื้นฐานในการพัฒนาเว็บ เราขอแนะนำให้ดู ส่วนขยาย 101 และ Hello 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 ซึ่งทำให้เรานำเข้าโมดูลใน Service Worker ได้
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
ผมจะอธิบายวิธีค้นหาบันทึกของ Service Worker และแจ้งให้ทราบเมื่อมีการยุติการทำงาน ก่อนอื่น ให้ทำตามวิธีการเพื่อโหลดส่วนขยายที่คลายการแพคแล้ว
หลังจาก 30 วินาที คุณจะเห็น "โปรแกรมทำงานของบริการ (ไม่ใช้งาน)" หมายความว่าโปรแกรมทำงานของบริการได้สิ้นสุดลงแล้ว คลิก "โปรแกรมทำงานของบริการ (ไม่ใช้งาน)" ลิงก์เพื่อตรวจสอบ ภาพเคลื่อนไหวต่อไปนี้แสดง
คุณสังเกตเห็นว่าการตรวจสอบ 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 จะปิดโปรแกรมทำงานของบริการหากไม่จำเป็น เราใช้ chrome.storage
API เพื่อคงสถานะไว้ในเซสชันของ 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
เพื่อจัดเก็บค่า นอกจากนี้ Service Worker ยังมีสภาพแวดล้อมการดำเนินการเป็นระยะเวลาสั้นๆ
ถูกสิ้นสุดการใช้งานซ้ำๆ ตลอดเซสชันเบราว์เซอร์ของผู้ใช้ ซึ่งทำให้ไม่สามารถใช้กับ
ตัวแปรร่วม แต่ให้ใช้ chrome.storage.local
ซึ่งจัดเก็บข้อมูลไว้ในเครื่องของคุณแทน
โปรดดูเก็บข้อมูลถาวรแทนการใช้ตัวแปรร่วมเพื่อดูข้อมูลเกี่ยวกับตัวเลือกพื้นที่เก็บข้อมูลอื่นๆ สำหรับโปรแกรมทำงานของบริการส่วนขยาย
ขั้นตอนที่ 5: ลงทะเบียนกิจกรรม
Listener เหตุการณ์ทั้งหมดต้องลงทะเบียนแบบคงที่ในขอบเขตทั่วโลกของ Service Worker กล่าวคือ Listener เหตุการณ์ไม่ควรฝังอยู่ในฟังก์ชันอะซิงโครนัส วิธีนี้ทำให้ Chrome ดูแลให้ตัวแฮนเดิลเหตุการณ์ทั้งหมดได้รับการกู้คืนในกรณีที่มีการรีบูตโปรแกรมทำงานของบริการ
ในตัวอย่างนี้ เราจะใช้ chrome.omnibox
API แต่ก่อนอื่นเราต้องประกาศทริกเกอร์คีย์เวิร์ดของแถบอเนกประสงค์ในไฟล์ 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 เหล่านี้อาจล้มเหลวเนื่องจากเครื่องจัดตารางเวลาจะยกเลิกตัวจับเวลาเมื่อบริการ
ผู้ปฏิบัติงานสิ้นสุดลง ส่วนขยายจะใช้ chrome.alarms
API แทนได้
เริ่มต้นด้วยการขอสิทธิ์ "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: สื่อสารกับบริบทอื่นๆ
ส่วนขยายใช้สคริปต์เนื้อหาในการอ่านและแก้ไขเนื้อหาของหน้าเว็บ เมื่อผู้ใช้ไปที่หน้าข้อมูลอ้างอิงของ Chrome API สคริปต์เนื้อหาของส่วนขยายจะอัปเดตหน้าดังกล่าวด้วยเคล็ดลับการใช้งานของวันนั้น ระบบจะส่งข้อความเพื่อขอเคล็ดลับของวันจาก Service Worker
เริ่มต้นด้วยการประกาศสคริปต์เนื้อหาในไฟล์ Manifest และเพิ่มรูปแบบการจับคู่ที่สอดคล้องกับเอกสารอ้างอิง Chrome API
manifest.json:
{
...
"content_scripts": [
{
"matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
"js": ["content.js"]
}
]
}
สร้างไฟล์เนื้อหาใหม่ รหัสต่อไปนี้จะส่งข้อความถึง Service Worker เพื่อขอเคล็ดลับ จากนั้นเพิ่มปุ่มที่จะเปิดป๊อปอัปที่มีเคล็ดลับส่วนขยาย โค้ดนี้ใช้แพลตฟอร์มเว็บใหม่ 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
- หรือเลือกจากรายการการค้นหาที่ผ่านมา
- หน้าใหม่จะเปิดขึ้นเป็นหน้าอ้างอิงของ Chrome API
ซึ่งควรมีลักษณะดังนี้
![การอ้างอิง API ด่วนการเปิดการอ้างอิง API รันไทม์](https://developer.chrome.com/static/docs/extensions/get-started/tutorial/service-worker-events/image/quick-api-reference-openi-5041b3b640769.gif?authuser=9&hl=th)
เปิดเคล็ดลับวันนี้
คลิกปุ่ม เคล็ดลับ ที่อยู่บนแถบนำทางเพื่อเปิดเคล็ดลับสำหรับส่วนขยาย
![เปิดเคล็ดลับประจำวันใน](https://developer.chrome.com/static/docs/extensions/get-started/tutorial/service-worker-events/image/open-daily-tip-676249a78de8e.gif?authuser=9&hl=th)
🎯 เพิ่มประสิทธิภาพได้
พยายามทำตามข้อใดต่อไปนี้โดยอิงจากสิ่งที่ได้เรียนรู้ในวันนี้
- สำรวจอีกวิธีในการนำคำแนะนำแถบอเนกประสงค์ไปใช้
- สร้างโมดัลที่กำหนดเองเพื่อแสดงเคล็ดลับสำหรับส่วนขยาย
- เปิดหน้าเพิ่มเติมเพื่อไปยังหน้า API อ้างอิงสำหรับส่วนขยายเว็บของ MDN
สร้างสรรค์ผลงานต่อไป!
ยินดีด้วยที่บทแนะนำนี้จบแล้ว 🎉 เพิ่มพูนทักษะของคุณอย่างต่อเนื่องโดยการพิชิตทักษะอื่นๆ บทแนะนำสำหรับผู้เริ่มต้น:
ส่วนขยาย | สิ่งที่คุณจะได้เรียนรู้ |
---|---|
เวลาในการอ่าน | เพื่อแทรกองค์ประกอบในหน้าเว็บชุดใดชุดหนึ่งโดยอัตโนมัติ |
ตัวจัดการแท็บ | เพื่อสร้างป๊อปอัปที่จัดการแท็บของเบราว์เซอร์ |
โหมดโฟกัส | หากต้องการเรียกใช้โค้ดในหน้าปัจจุบันหลังจากคลิกการดำเนินการของส่วนขยาย |
สำรวจต่อ
หากต้องการดำเนินการต่อในเส้นทางการเรียนรู้สำหรับโปรแกรมทำงานของส่วนขยาย เราขอแนะนำให้อ่านบทความต่อไปนี้