ข้ามไปยังเนื้อหา

กลยุทธ์ Service Worker

@vite-pwa/astro มีสองวิธีในการสร้าง service worker ของคุณ ได้แก่ generateSW (ค่าเริ่มต้น) และ injectManifest การเลือกวิธีที่เหมาะสมขึ้นอยู่กับว่าคุณต้องการควบคุม fetch handling มากแค่ไหน

ด้วย generateSW Vite PWA จะเขียน service worker ทั้งหมดให้คุณ คุณเพียงแค่ระบุ configuration object ใต้ key workbox แล้ว Workbox จะ generate sw.js ขึ้นมาในขั้นตอน build นี่คือตัวเลือกที่ถูกต้องสำหรับเว็บไซต์ Astro ส่วนใหญ่: การ precaching output ของ static build บวกกับ runtime caching rules สองสามข้อครอบคลุมความต้องการในโลกจริงส่วนใหญ่ โดยไม่ต้องดูแล service worker code เลย

ตั้งค่า registerType: 'autoUpdate' เพื่อให้ service worker ใหม่ install และ activate แบบเงียบๆ ทุกครั้งที่คุณ deploy การอัปเดต ผู้ใช้จะได้รับเวอร์ชันล่าสุดเสมอโดยไม่เห็น prompt ใดๆ

astro.config.mjs
AstroPWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 },
},
},
{
urlPattern: /^https:\/\/api\.example\.com\/.*/i,
handler: 'NetworkFirst',
options: { cacheName: 'api-cache', networkTimeoutSeconds: 5 },
},
],
},
})

globPatterns กำหนดว่าไฟล์ที่ build แล้วไฟล์ใดบ้างที่จะถูกเพิ่มเข้าไปใน precache manifest — ไฟล์เหล่านี้จะถูกดาวน์โหลดตอน install และ serve จาก cache ในทุกครั้งที่เข้าชมครั้งถัดไป แม้จะออฟไลน์ Array runtimeCaching เพิ่ม caching rules ที่จะทำงานตอน fetch สำหรับ URL ที่ตรงกับ pattern แต่ละอัน CacheFirst เหมาะสำหรับ asset ที่ไม่เปลี่ยนแปลงอย่างฟอนต์ ส่วน NetworkFirst เหมาะสำหรับ API endpoint ที่ความใหม่ของข้อมูลมีความสำคัญ

เมื่อคุณต้องการ custom fetch logic — routing ขั้นสูง, background sync, push notifications หรืออะไรก็ตามที่ Workbox ไม่สามารถ generate ให้อัตโนมัติได้ — ให้เปลี่ยนไปใช้ injectManifest คุณเขียน src/sw.ts เอง; ในขั้นตอน build Vite PWA จะ compile ไฟล์นี้แล้วฉีด precache manifest เข้าไปผ่าน placeholder self.__WB_MANIFEST

astro.config.mjs
AstroPWA({
strategies: 'injectManifest',
srcDir: 'src',
filename: 'sw.ts',
})
// src/sw.ts (your custom service worker)
import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching'
declare let self: ServiceWorkerGlobalScope
cleanupOutdatedCaches()
precacheAndRoute(self.__WB_MANIFEST)
self.addEventListener('fetch', (event) => {
// your custom fetch logic here
})

precacheAndRoute(self.__WB_MANIFEST) แทนที่ placeholder ด้วย manifest list จริงในขั้นตอน build ทำให้คุณได้ทั้ง automatic precaching และ custom fetch handling ที่คุณเพิ่มเข้าไป

เมื่อ registerType เป็น 'prompt' service worker จะรอให้ code ของคุณ trigger การอัปเดต import registerSW จาก virtual module virtual:pwa-register เพื่อเชื่อมต่อ UI ยืนยัน:

src/pwa.ts
import { registerSW } from 'virtual:pwa-register'
const updateSW = registerSW({
onNeedRefresh() {
if (confirm('New content available. Reload?')) {
updateSW(true)
}
},
onOfflineReady() {
console.log('App ready to work offline')
},
})
src/components/PwaInit.astro
<script>
import './pwa.ts'
</script>

เพิ่ม <PwaInit /> ใน root layout ของคุณเพื่อให้ registration logic ทำงานในทุกหน้า หากใช้ autoUpdate คุณสามารถข้ามขั้นตอนนี้ได้ทั้งหมด เพราะไม่มีอะไรต้องเรียก updateSW(true) เนื่องจากการอัปเดตถูก apply อัตโนมัติ

flowchart TD
  A[Need custom SW logic?] -->|No| B[generateSW]
  A -->|Yes| C[injectManifest]
  B --> D[Workbox generates sw.js automatically]
  C --> E[You write src/sw.ts with workbox-precaching]
  D --> F[Configure via workbox: options]
  E --> G[Full control over fetch handling]
แผนผังการตัดสินใจ generateSW vs injectManifest
ตัวเลือกBenefitCost
generateSW (Workbox generate อัตโนมัติ)เริ่มต้นเร็วที่สุด ไม่ต้องเขียน service worker เองปรับแต่ง logic เฉพาะทำได้จำกัดกว่าการเขียนเอง
injectManifest (เขียน service worker เอง + inject precache list)ควบคุม logic ได้เต็มที่ ผสม custom logic ได้อิสระต้องเขียนและ maintain service worker file เอง เพิ่ม complexity
  • เลือก generateSW แล้วพยายามเพิ่ม custom logic ที่ mode นี้ไม่รองรับ ทำให้ต้องย้ายไป injectManifest ทีหลัง เสียเวลา refactor
  • ไม่ตั้ง strategy ให้ตรงกับประเภท route ของ Astro (static page vs API endpoint) ทำให้ cache ผิดประเภท
  • ลืมว่า Astro build output เปลี่ยน asset hash ทุกครั้ง ทำให้ precache manifest เก่าที่ generate ไว้ไม่ตรงกับไฟล์จริงถ้าไม่ rebuild

💡 ตัวอย่างจากของจริง

@vite-pwa/astro ecosystem — ให้ทั้งสอง mode นี้เป็นทางเลือก โปรเจกต์ documentation ส่วนใหญ่ใช้ generateSW เพราะพอสำหรับ static site

แอปที่มี custom offline logic ซับซ้อน — เลือก injectManifest เพื่อผสม custom fetch handler เข้ากับ precache list ที่ Workbox generate ให้

กลยุทธ์ใดที่ให้ Workbox generate ไฟล์ service worker ทั้งหมดอัตโนมัติจาก config object?
registerType: "autoUpdate" ทำอะไรเมื่อมี service worker ใหม่พร้อมใช้งาน?
virtual:pwa-register module มีจุดประสงค์อะไร?
ใน service worker แบบ injectManifest การเรียก precacheAndRoute(self.__WB_MANIFEST) ทำอะไร?