สร้าง Chrome Extension Pomodoro บน MV3 แบบทีละขั้นตอน
บทความนี้สรุปแนวทางสร้าง Chrome Extension สำหรับ Pomodoro Timer พร้อมแจ้งเตือนพักสายตา โดยเน้นการใช้ Manifest V3, service worker, chrome.alarms, notifications และ storage อย่างถูกต้องเพื่อให้ระบบเสถียรและไม่หลุดหลังรีสตา

สร้าง Chrome Extension Pomodoro บน MV3 แบบทีละขั้นตอน
การทำ Chrome Extension สำหรับ Pomodoro Timer เป็นโปรเจกต์ที่ดีมากสำหรับฝึกการทำงานกับ Manifest V3 และ API สำคัญของ Chrome ไม่ว่าจะเป็น service worker, chrome.alarms, chrome.notifications และ chrome.storage โดยโจทย์นี้ไม่ได้มีแค่เรื่องการนับเวลา แต่ยังรวมถึงการออกแบบสถานะ การแจ้งเตือนพักสายตา และการทำให้ extension กลับมาทำงานต่อได้แม้ Chrome ถูกปิดหรือ worker หลับไป
โปรเจกต์นี้มีเป้าหมายหลักคือสร้างตัวจับเวลา Pomodoro บนแถบเครื่องมือ ที่กดเริ่มหรือหยุดได้ง่าย มีการแจ้งเตือนเมื่อถึงเวลาพักหรือกลับมาทำงาน และเก็บสถานะไว้เพื่อให้ใช้งานต่อเนื่องได้อย่างมืออาชีพ
ภาพรวมการทำงานของ Extension
ลำดับการทำงานของ extension สามารถออกแบบได้ดังนี้
- ผู้ใช้กดไอคอน Extension เพื่อเริ่มหรือหยุดการจับเวลา
- ตัวจับเวลาทำงานอยู่เบื้องหลังด้วย
chrome.alarms - เมื่อครบช่วงทำงานหรือพัก ระบบจะแสดง notification
- สถานะทั้งหมดจะถูกเก็บไว้ใน
chrome.storageเพื่อป้องกันข้อมูลหายระหว่างการรีสตาร์ท
แนวคิดนี้ช่วยให้ extension ไม่พึ่งการเปิด popup ค้างไว้ และทำให้ระบบยังมีความเสถียรแม้ service worker จะถูกพักการทำงานชั่วคราว
สิ่งสำคัญที่ต้องเข้าใจก่อนเริ่ม
ใน Manifest V3 ไม่มี background page แบบเดิมอีกต่อไป แต่เปลี่ยนมาใช้ service worker ซึ่งมีลักษณะสำคัญคือสามารถ “หลับ” ได้เมื่อไม่มีงานให้ทำ นั่นหมายความว่าเราไม่ควรพึ่ง setInterval หรือ setTimeout ในการนับเวลาแบบต่อเนื่อง เพราะไม่เสถียรพอสำหรับงานลักษณะนี้
วิธีที่เหมาะสมกว่าคือใช้ chrome.alarms เป็นกลไกหลักในการจัดการเวลา เพราะถูกออกแบบมาเพื่อทำงานในสภาพแวดล้อมของ extension บน MV3 โดยเฉพาะ
โครงสร้างไฟล์ที่แนะนำ
โครงสร้างไฟล์พื้นฐานของโปรเจกต์ควรมีดังนี้
manifest.jsonservice_worker.jspopup.htmlpopup.jsicons/สำหรับไอคอนขนาด 16, 48 และ 128
การแยกไฟล์ลักษณะนี้ช่วยให้ดูแลโค้ดง่าย โดยให้ popup รับหน้าที่เป็น UI และให้ service worker เป็นศูนย์กลางของ logic ทั้งหมด
ขั้นที่ 1: สร้าง manifest.json
ไฟล์ manifest.json คือหัวใจของ extension โดยต้องตั้งค่า manifest_version เป็น 3 และกำหนด permission ที่จำเป็น เช่น
alarmsnotificationsstorageaction
นอกจากนี้ต้องกำหนด background.service_worker ให้ชี้ไปยัง service_worker.js และกำหนด default_popup เป็น popup.html เพื่อให้ไอคอนบนแถบเครื่องมือเปิดหน้าควบคุมได้ทันที
ขั้นที่ 2: ออกแบบสถานะที่จะเก็บใน storage
การออกแบบ state ให้ชัดตั้งแต่แรกสำคัญมาก เพราะจะส่งผลต่อความง่ายในการขยายระบบภายหลัง โครงสร้างที่แนะนำ เช่น
mode:workหรือbreakisRunning:trueหรือfalseendAt: timestamp แบบ millisecond ที่บอกเวลาจบของรอบปัจจุบันworkMinutes: เช่น 25breakMinutes: เช่น 5cycleCount: จำนวนรอบที่ทำไปแล้ว
จุดสำคัญคือไม่ควรเก็บแค่ “เวลาที่เหลือ” เพียงอย่างเดียว แต่ควรเก็บ endAt ด้วย เพราะจะทำให้สามารถคำนวณเวลาคงเหลือใหม่ได้เสมอ แม้ worker จะหลับหรือถูกรีสตาร์ทก็ตาม
ขั้นที่ 3: ออกแบบ popup ให้เรียบง่ายแต่ใช้งานจริง
popup ควรเป็นหน้าควบคุมที่ใช้งานง่ายและไม่ซับซ้อนเกินไป โดยอาจมีองค์ประกอบหลักดังนี้
- ปุ่ม
Start/Stop - ปุ่ม
Reset - ช่องตั้งค่าเวลาสำหรับ Work และ Break
- พื้นที่แสดงโหมดปัจจุบันและเวลาที่เหลือ
หลักการสำคัญคือต้องมองว่า popup เป็นเพียง UI เท่านั้น ไม่ใช่แหล่งเก็บสถานะจริง ทุกครั้งที่ popup ถูกเปิดขึ้นมาใหม่ ควรอ่านข้อมูลจาก storage แล้ว render ใหม่เสมอ เพื่อให้ข้อมูลตรงกับสภาพจริงของระบบ
ขั้นที่ 4: ให้ service worker เป็นศูนย์กลางของระบบ
service worker ควรเป็นตัวควบคุมหลักของ extension โดยมีหน้าที่สำคัญหลายอย่าง ได้แก่
- ฟัง event จาก popup ผ่าน
chrome.runtime.onMessage - ตั้ง alarm สำหรับการจบช่วง work หรือ break
- อัปเดต badge บนไอคอน extension
- สร้าง notification เมื่อครบเวลา
- บันทึก state ลง
storageทุกครั้งที่มีการเปลี่ยนแปลง
การรวม logic สำคัญไว้ที่ worker ช่วยลดความสับสนและป้องกันปัญหาที่เกิดจาก popup ถูกปิดระหว่างการใช้งาน
ขั้นที่ 5: ตั้ง alarm ให้เหมาะกับการจับเวลา
เมื่อเริ่มรอบใหม่ ควรคำนวณ endAt = now + minutes * 60 * 1000 แล้วสร้าง alarm อย่างน้อย 2 แบบ คือ
tickสำหรับอัปเดต badge ทุก 1 นาทีfinishสำหรับแจ้งเมื่อถึงเวลาจบรอบ
ข้อควรรู้คือ chrome.alarms มีความละเอียดระดับนาทีในหลายกรณี จึงไม่เหมาะกับการแสดงผลแบบนับถอยหลังทีละวินาที แนวทางที่ดีคือใช้ badge แสดงจำนวน “นาทีที่เหลือ” และแสดงรายละเอียดมากขึ้นภายใน popup เมื่อต้องการดูสถานะล่าสุด
ขั้นที่ 6: ทำ notifications ให้มีประโยชน์และไม่รบกวนเกินไป
Notification ที่ดีไม่ควรมีไว้เพียงเพื่อบอกว่าหมดเวลา แต่ควรช่วยเปลี่ยนพฤติกรรมของผู้ใช้ด้วย เช่น
- เมื่อจบรอบ work: แจ้งให้พักสายตา 20 วินาที และลุกยืดเส้น
- เมื่อจบรอบ break: แจ้งให้กลับมาโฟกัสกับงานรอบใหม่
หาก notification ไม่แสดง ควรตรวจสอบการอนุญาตแจ้งเตือนทั้งใน Chrome และในระบบปฏิบัติการด้วย เพราะบางครั้งปัญหาไม่ได้อยู่ที่โค้ด แต่เป็นการตั้งค่าระบบของผู้ใช้
ขั้นที่ 7: เพิ่มกติกาพักสายตา 20-20-20
นอกจาก Pomodoro ปกติแล้ว ยังสามารถเพิ่มแนวคิด 20-20-20 เพื่อช่วยลดอาการล้าจากการจ้องหน้าจอได้ โดยหลักคือทุก 20 นาที ให้มองไกล 20 ฟุต เป็นเวลา 20 วินาที
สามารถออกแบบได้ 2 แนวทาง
- เตือนพร้อมกับจบรอบ Pomodoro
- แยก alarm
eyeBreakทุก 20 นาที ระหว่างที่isRunning = true
หากผู้ใช้ทำงานหน้าจอหนักมาก วิธีที่สองจะเหมาะกว่า เพราะช่วยให้พักสายตาถี่ขึ้น ไม่ต้องรอให้ครบ Pomodoro ก่อน
ขั้นที่ 8: การสื่อสารระหว่าง popup กับ worker
การส่งคำสั่งระหว่าง popup และ worker ควรใช้ chrome.runtime.sendMessage โดยกำหนดชนิดข้อความให้ชัดเจน เช่น
STARTSTOPRESETSETTINGS_UPDATEGET_STATE
รูปแบบการทำงานที่ดีคือ popup ส่งคำสั่งไปยัง worker จากนั้น worker ประมวลผล อัปเดต state แล้วตอบค่าล่าสุดกลับมา เพื่อให้ popup นำไปแสดงผลอีกครั้ง วิธีนี้ทำให้การควบคุมมีทิศทางเดียวและตรวจสอบปัญหาได้ง่าย
ขั้นที่ 9: ทำให้ระบบไม่หลุดหลังรีสตาร์ท Chrome
จุดที่ทำให้ extension ดู “โปร” จริง ๆ คือความสามารถในการกลับมาทำงานต่อหลัง Chrome หรือ service worker ถูกรีสตาร์ท โดยเมื่อ worker เริ่มทำงาน ควรอ่าน state จาก storage ก่อนเสมอ
หากพบว่า isRunning = true ต้องตรวจต่อว่าเวลาปัจจุบันเลย endAt ไปแล้วหรือไม่
- ถ้ายังไม่เลย ให้ตั้ง alarms ใหม่ตาม state เดิม
- ถ้าเลยแล้ว ให้สลับโหมด ปรับ
endAtใหม่ และตั้ง alarms ใหม่ทั้งหมด
ขั้นตอนนี้เรียกว่าแนวคิดการ rehydrate state ซึ่งเป็นรายละเอียดที่หลาย extension มักพลาด และเป็นสาเหตุให้ตัวจับเวลาหลุดหรือแสดงผลผิดพลาดหลังกลับมาใช้งานอีกครั้ง
ขั้นที่ 10: ใช้ badge ให้เกิดประโยชน์
badge บนไอคอน extension เป็นพื้นที่เล็ก ๆ แต่มีประโยชน์มาก เพราะช่วยให้ผู้ใช้เห็นสถานะได้ทันทีโดยไม่ต้องเปิด popup ขึ้นมาดูตลอดเวลา
แนวทางที่แนะนำคือ
- แสดงเลขจำนวนนาทีที่เหลือ เช่น
12 - ใช้สีแดงเข้มเมื่ออยู่ในโหมด work
- ใช้สีเขียวเมื่ออยู่ในโหมด break
เพื่อไม่ให้ worker ตื่นถี่เกินไป ควรอัปเดต badge แค่ระดับนาทีผ่าน alarm tick ก็เพียงพอแล้ว
ขั้นที่ 11: เช็กลิสต์สำหรับ debug อย่างรวดเร็ว
หาก extension ไม่ทำงาน ควรเริ่มตรวจจากจุดพื้นฐานเหล่านี้
Extension ไม่ทำงาน
- เข้าไปที่
chrome://extensions - เปิด Developer mode
- กด Inspect views ของ service worker
- ดู Console ว่ามี error ที่เกี่ยวกับ manifest หรือ permission หรือไม่
Notifications ไม่ขึ้น
- ตรวจว่าใส่ permission
notificationsใน manifest แล้ว - ลองใช้
chrome.notifications.createด้วย id ที่ไม่ซ้ำกัน - ตรวจการตั้งค่าแจ้งเตือนของ Chrome และระบบปฏิบัติการ
Alarms ไม่ยิง
- ตรวจว่ามีการใช้
chrome.alarms.onAlarm.addListenerแล้ว - ตรวจว่าชื่อ alarm ที่สร้างและชื่อที่เช็คตรงกัน
แนวทางต่อยอดที่น่าสนใจ
เมื่อระบบพื้นฐานทำงานได้แล้ว ยังสามารถต่อยอดให้มีประโยชน์มากขึ้นได้อีก เช่น
- เก็บสถิติรายวัน เช่น จำนวนเวลาที่โฟกัสได้ในแต่ละวัน
- เพิ่มเสียงแจ้งเตือนสั้น ๆ
- ทำโหมด
Do Not Disturbสำหรับช่วงประชุม - ใช้
chrome.storage.syncเพื่อซิงก์ข้อมูลข้ามเครื่อง โดยต้องระวังเรื่องโควตาการใช้งาน
แนวทางเหล่านี้ช่วยยกระดับจาก extension ทดลองเล่น ให้กลายเป็นเครื่องมือที่ใช้งานได้จริงในชีวิตประจำวัน
สรุป
การสร้าง Pomodoro Extension บน Manifest V3 ให้เสถียร ควรยึด 3 แกนหลักคือ
- ใช้
storageสำหรับเก็บ state - ใช้
alarmsเป็นกลไกหลักในการขับเคลื่อนเวลา - ใช้
notificationsเป็น feedback ให้ผู้ใช้
เมื่อทั้งสามส่วนทำงานร่วมกันอย่างถูกต้อง extension จะมีความนิ่ง ใช้งานต่อเนื่องได้แม้ worker หลับหรือ Chrome รีสตาร์ท และให้ประสบการณ์ที่ดูเป็นมืออาชีพมากขึ้นอย่างชัดเจน