Workbox
Workbox
หัวข้อที่มีชื่อว่า “Workbox”Workbox คือชุด library จากทีม Chrome ที่ทำให้รูปแบบ Cache Storage และ fetch-event ระดับล่างที่คุณเขียนด้วยมือมาตลอดกลายเป็นนามธรรม แทนที่จะเขียน logic แบบ cache-first ขึ้นมาเองตั้งแต่ต้น คุณก็แค่เรียก new CacheFirst() แทนที่จะจัดการเวอร์ชันของ cache ด้วยมือ precaching manifest ของ Workbox ก็จัดการให้ ผลลัพธ์คือ boilerplate น้อยลง บั๊กในเคสมุมน้อยลง และโมเดลการ caching ที่สอดคล้องกันทั้งแอป
การติดตั้ง Workbox
หัวข้อที่มีชื่อว่า “การติดตั้ง Workbox”Workbox ถูกแบ่งเป็นแพ็กเกจที่โฟกัสเฉพาะเรื่อง คุณจึง ship เฉพาะส่วนที่ใช้ ติดตั้งแพ็กเกจที่เกี่ยวข้องกับบทเรียนนี้:
npm install workbox-routing workbox-strategies workbox-precaching workbox-expirationแต่ละแพ็กเกจมีหน้าที่ชัดเจน:
workbox-routing— ให้registerRouteสำหรับ map รูปแบบ request ไปยัง strategy handlerworkbox-strategies— ให้ strategy class ต่าง ๆ:CacheFirst,NetworkFirst,StaleWhileRevalidate, และอื่น ๆworkbox-precaching— ให้precacheAndRouteสำหรับติดตั้ง asset manifest ตอน buildworkbox-expiration— ให้ExpirationPluginสำหรับจำกัดขนาด cache และอายุของรายการ
registerRoute และ strategy
หัวข้อที่มีชื่อว่า “registerRoute และ strategy”registerRoute รับ route matcher (เป็น string, RegExp, หรือ callback ที่รับ route context) และ strategy handler instance หนึ่งตัว เมื่อ fetch event เกิดขึ้น Workbox จะวนดู route ที่ลงทะเบียนไว้ หาตัวที่ตรงตัวแรก แล้วมอบหมายการตอบกลับให้ strategy ที่เชื่อมโยงไว้
import { registerRoute } from 'workbox-routing';import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
// Static assets — cache-firstregisterRoute( ({ request }) => request.destination === 'image', new CacheFirst({ cacheName: 'images-v1' }));
// API data — network-firstregisterRoute( ({ url }) => url.pathname.startsWith('/api/'), new NetworkFirst({ cacheName: 'api-v1' }));
// Avatars and feeds — stale-while-revalidateregisterRoute( ({ request }) => request.destination === 'document', new StaleWhileRevalidate({ cacheName: 'pages-v1' }));ใช้ CacheFirst สำหรับ asset ที่แทบไม่เปลี่ยน (รูปภาพ, ฟอนต์, JS bundle ที่มีเวอร์ชัน) ใช้ NetworkFirst สำหรับข้อมูลไดนามิกที่ความสดใหม่เป็นเรื่องสำคัญ (การตอบกลับจาก API) ใช้ StaleWhileRevalidate เมื่อคุณต้องการเวลาโหลดทันทีและยินดีที่จะแสดงข้อมูลที่เก่าไปหนึ่ง request (เอกสาร HTML, รูป avatar, ฟีด RSS)
การ precache ด้วย manifest
หัวข้อที่มีชื่อว่า “การ precache ด้วย manifest”Workbox สามารถ precache รายการไฟล์ที่ถูกสร้างตอน build ได้ manifest เป็น array ของรายการ { url, revision } ตอน runtime การ precaching ของ Workbox จะติดตั้งไฟล์ทั้งหมดที่ระบุไว้ระหว่าง install event ของ service worker และจัดการ cache-busting อัตโนมัติผ่าน revision hash — เมื่อไฟล์เปลี่ยน revision hash ของตัวเองก็เปลี่ยน และ Workbox จะแทนที่เฉพาะรายการนั้น
import { precacheAndRoute } from 'workbox-precaching';
// __WB_MANIFEST is injected by the Workbox build tool / vite-plugin-pwaprecacheAndRoute(self.__WB_MANIFEST);self.__WB_MANIFEST คือ placeholder string ที่ Workbox build tool (หรือ vite-plugin-pwa) แทนที่ตอน build ด้วย array ของ manifest จริง ตัวอย่างเช่น:
[ { url: '/index.html', revision: 'abc123' }, { url: '/assets/main.js', revision: 'def456' }, { url: '/assets/style.css', revision: 'ghi789' },]คุณไม่เคยต้องเขียน array นี้ด้วยมือ — Workbox สร้างให้อัตโนมัติจากผลลัพธ์ build ของคุณ
ExpirationPlugin
หัวข้อที่มีชื่อว่า “ExpirationPlugin”หากไม่มีการจำกัด expiration cache สามารถโตได้ไม่จำกัดและกินพื้นที่จัดเก็บของอุปกรณ์อย่างมาก ExpirationPlugin บังคับใช้สองข้อจำกัด: maxEntries จำกัดจำนวน response ที่แคชไว้ และ maxAgeSeconds ลบ response ที่เก่ากว่าระยะเวลาที่กำหนด
import { CacheFirst } from 'workbox-strategies';import { ExpirationPlugin } from 'workbox-expiration';
registerRoute( ({ request }) => request.destination === 'image', new CacheFirst({ cacheName: 'images-v1', plugins: [ new ExpirationPlugin({ maxEntries: 60, maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days }), ], }));เมื่อ cache แตะ 60 รายการ รายการที่ถูกใช้ล่าสุดน้อยที่สุด (least-recently-used) จะถูก evict ออก รายการใดก็ตามที่เก่ากว่า 30 วันจะถูกลบในรอบการเคลียร์ครั้งถัดไป ทั้งสองข้อจำกัดสามารถใช้ร่วมกันใน plugin instance เดียวกันได้
vite-plugin-pwa
หัวข้อที่มีชื่อว่า “vite-plugin-pwa”หากคุณใช้ Vite (กับ React, Vue, Svelte, หรือ JS ล้วน ๆ) vite-plugin-pwa จะผนวก Workbox เข้ากับ build pipeline ของคุณโดยอัตโนมัติ plugin จะสร้างไฟล์ SW พร้อม precaching manifest จัดการ cache versioning ในทุก build และลงทะเบียน SW ในแอปของคุณ — โดยไม่ต้องดูแล self.__WB_MANIFEST ด้วยมือเลย ตั้งค่าใน vite.config.ts:
import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({ plugins: [ VitePWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg}'], runtimeCaching: [ { urlPattern: /^https:\/\/api\.example\.com\//, handler: 'NetworkFirst', options: { cacheName: 'api-cache' }, }, ], }, }), ],});globPatterns ควบคุมว่าไฟล์ผลลัพธ์ build ใดบ้างที่จะเข้า precache manifest runtimeCaching เพิ่มการเรียก registerRoute สำหรับ URL ที่ไม่ได้เป็นส่วนหนึ่งของผลลัพธ์ build — เช่น API ภายนอก ส่วน string ของ handler map ไปยังชื่อ strategy class ของ Workbox
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| ใช้ Workbox แทนเขียน service worker เอง | ลด boilerplate เยอะมาก มี strategy สำเร็จรูปและ routing ให้พร้อม | เพิ่ม dependency และ bundle size บางส่วน ต้องเรียนรู้ config เฉพาะของ Workbox |
| เขียน service worker เปล่าด้วยมือ | ควบคุมทุกบรรทัด ไม่มี abstraction แทรก | ต้อง reinvent cache versioning, routing, precache manifest เองทั้งหมด |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ใช้ผิด strategy กับผิดประเภท route (เช่น CacheFirst กับ API ที่เปลี่ยนบ่อย) เพราะ copy config จากตัวอย่างมาโดยไม่เข้าใจ
- ไม่ regenerate precache manifest หลัง build ทำให้ Workbox precache ไฟล์เวอร์ชันเก่าที่ hash ไม่ตรงกับไฟล์จริง
- ลืมว่า Workbox ยังต้องเรียก
self.skipWaiting()/clients.claim()เองถ้าต้องการ auto-update ไม่ใช่ default ของ library
💡 ตัวอย่างจากของจริง
Twitter Lite / Pinterest — เป็นสองเคสที่ทีม Google อ้างถึงบ่อยที่สุดว่าใช้ Workbox จัดการ caching strategy ระดับ production
Google I/O web app — ใช้ Workbox precaching ร่วมกับ build tool เพื่อให้ asset ทุกตัว versioned อัตโนมัติทุกครั้งที่ deploy