โมดูล $service-worker
Vanilla SvelteKit service workers
หัวข้อที่มีชื่อว่า “Vanilla SvelteKit service workers”SvelteKit จะ bundle และลงทะเบียนไฟล์ใดก็ตามที่คุณวางไว้ที่ src/service-worker.js (หรือ .ts) โดยอัตโนมัติ ภายในไฟล์นั้น virtual module $service-worker จะให้ทุกอย่างที่คุณต้องการในการเขียน service worker สำหรับ precache ที่แข็งแกร่งโดยไม่ต้องใช้ไลบรารี third-party ใดๆ
สิ่งที่ $service-worker export ออกมา
หัวข้อที่มีชื่อว่า “สิ่งที่ $service-worker export ออกมา”| Export | ประเภท | เนื้อหา |
|---|---|---|
build | string[] | Client-side asset ที่มี hash (_app/immutable/…) |
files | string[] | ทุกอย่างที่คัดลอกมาจาก static/ |
version | string | String เฉพาะตัวที่เปลี่ยนในทุก build |
prerendered | string[] | Path ของ HTML page ที่ prerender แล้ว |
build และ files รวมกันครอบคลุม asset ทั้งหมดที่แอปของคุณต้องการเพื่อทำงาน offline version สร้างชื่อ cache เฉพาะตัว เพื่อให้ cache เก่าถูกล้างออกอย่างน่าเชื่อถือหลังจาก deploy ใหม่แต่ละครั้ง
สร้าง src/service-worker.js
หัวข้อที่มีชื่อว่า “สร้าง src/service-worker.js”/// <reference types="@sveltejs/kit" />import { build, files, version, prerendered } from '$service-worker';
const CACHE = `cache-\${version}`;
const ASSETS = [ ...build, // hashed JS/CSS bundles ...files, // static/ assets (icons, fonts, …) ...prerendered, // prerendered HTML pages];
// -- Install: precache all assets ----------------------------------------------self.addEventListener('install', (event) => { async function addFilesToCache() { const cache = await caches.open(CACHE); await cache.addAll(ASSETS); } event.waitUntil(addFilesToCache());});
// -- Activate: delete old caches -----------------------------------------------self.addEventListener('activate', (event) => { async function deleteOldCaches() { for (const key of await caches.keys()) { if (key !== CACHE) await caches.delete(key); } } event.waitUntil(deleteOldCaches());});
// -- Fetch: serve from cache, fall back to network -----------------------------self.addEventListener('fetch', (event) => { if (event.request.method !== 'GET') return;
async function respond() { const url = new URL(event.request.url); const cache = await caches.open(CACHE);
// Always serve build/files assets from cache (they are hashed) if (ASSETS.includes(url.pathname)) { const cached = await cache.match(url.pathname); if (cached) return cached; }
// For everything else: network first, cache as fallback try { const response = await fetch(event.request); if (response.status === 200) { cache.put(event.request, response.clone()); } return response; } catch { const cached = await cache.match(event.request); if (cached) return cached; throw new Error('No cached response and network unavailable'); } }
event.respondWith(respond());});ทำไมชื่อ cache ถึงใช้ version
หัวข้อที่มีชื่อว่า “ทำไมชื่อ cache ถึงใช้ version”ทุก SvelteKit build สร้าง version string ใหม่ที่ได้มาจาก build timestamp และ content hash รูปแบบ `cache-\${version}` หมายความว่าแต่ละ deployment จะมี cache ของตัวเองแบบ isolated handler activate จะลบ cache ทุกอันที่ชื่อไม่ตรงกับ version ปัจจุบัน — ล้าง storage จาก deploy ก่อนหน้าทั้งหมดโดยอัตโนมัติ
เวอร์ชัน TypeScript
หัวข้อที่มีชื่อว่า “เวอร์ชัน TypeScript”สำหรับโปรเจกต์ TypeScript ให้เปลี่ยนชื่อไฟล์เป็น src/service-worker.ts และเพิ่ม reference directive เพื่อให้ SW global มี type ที่ถูกต้อง:
/// <reference types="@sveltejs/kit" />import { build, files, version, prerendered } from '$service-worker';
declare const self: ServiceWorkerGlobalScope;
const CACHE = `cache-\${version}`;// … ส่วนที่เหลือของไฟล์เหมือนกันแล้ว prerendered ล่ะ?
หัวข้อที่มีชื่อว่า “แล้ว prerendered ล่ะ?”หากแอปของคุณ prerender หน้าต่างๆ (ผ่าน export const prerender = true ในไฟล์ route หรือ adapter-static) SvelteKit จะเติม prerendered ด้วย path ของหน้าเหล่านั้น การรวมไว้ใน ASSETS หมายความว่าหน้าเหล่านั้นจะโหลดทันทีแม้ offline โดยไม่ต้องเชื่อมต่อเครือข่าย
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
ใช้ $service-worker module ของ SvelteKit | เข้าถึง build manifest (asset list, version) ได้ตรงๆ จาก SvelteKit เอง | ผูกกับ SvelteKit convention เฉพาะ ย้ายไป framework อื่นต้องเขียนใหม่ |
| เขียน service worker แบบ static ไม่พึ่ง SvelteKit module | ทำงานได้แม้นอก SvelteKit build pipeline | ต้อง maintain asset list เองแทนที่จะให้ framework generate ให้ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- import
$service-workerผิด context (ใช้นอกไฟล์ service worker) ทำให้ build error เพราะ module นี้ resolve เฉพาะตอน build service worker เท่านั้น - ไม่ใช้
buildและfilesที่ export มาจาก module นี้ในการ precache ทำให้ต้อง list asset เองด้วยมือและหลุด sync กับ build จริง - ลืมว่า
versionจาก module นี้เปลี่ยนทุก build ทำให้ถ้าไม่ใช้ตั้งชื่อ cache จะ invalidate cache เก่าไม่ถูกจังหวะ
💡 ตัวอย่างจากของจริง
SvelteKit official service worker docs — ใช้
$service-workerเป็นแนวทางมาตรฐานสำหรับทุกโปรเจกต์ SvelteKit ที่ต้องการ precache แบบ build-awareVite PWA ecosystem (SvelteKit-based projects) — โปรเจกต์จำนวนมากที่ใช้ SvelteKit ต่อยอดจาก module นี้เพื่อทำ offline-first app