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

โมดูล $service-worker

SvelteKit จะ bundle และลงทะเบียนไฟล์ใดก็ตามที่คุณวางไว้ที่ src/service-worker.js (หรือ .ts) โดยอัตโนมัติ ภายในไฟล์นั้น virtual module $service-worker จะให้ทุกอย่างที่คุณต้องการในการเขียน service worker สำหรับ precache ที่แข็งแกร่งโดยไม่ต้องใช้ไลบรารี third-party ใดๆ

Exportประเภทเนื้อหา
buildstring[]Client-side asset ที่มี hash (_app/immutable/…)
filesstring[]ทุกอย่างที่คัดลอกมาจาก static/
versionstringString เฉพาะตัวที่เปลี่ยนในทุก build
prerenderedstring[]Path ของ HTML page ที่ prerender แล้ว

build และ files รวมกันครอบคลุม asset ทั้งหมดที่แอปของคุณต้องการเพื่อทำงาน offline version สร้างชื่อ cache เฉพาะตัว เพื่อให้ cache เก่าถูกล้างออกอย่างน่าเชื่อถือหลังจาก deploy ใหม่แต่ละครั้ง

/// <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());
});

ทุก SvelteKit build สร้าง version string ใหม่ที่ได้มาจาก build timestamp และ content hash รูปแบบ `cache-\${version}` หมายความว่าแต่ละ deployment จะมี cache ของตัวเองแบบ isolated handler activate จะลบ cache ทุกอันที่ชื่อไม่ตรงกับ version ปัจจุบัน — ล้าง storage จาก deploy ก่อนหน้าทั้งหมดโดยอัตโนมัติ

สำหรับโปรเจกต์ 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}`;
// … ส่วนที่เหลือของไฟล์เหมือนกัน

หากแอปของคุณ prerender หน้าต่างๆ (ผ่าน export const prerender = true ในไฟล์ route หรือ adapter-static) SvelteKit จะเติม prerendered ด้วย path ของหน้าเหล่านั้น การรวมไว้ใน ASSETS หมายความว่าหน้าเหล่านั้นจะโหลดทันทีแม้ offline โดยไม่ต้องเชื่อมต่อเครือข่าย

ตัวเลือกBenefitCost
ใช้ $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-aware

Vite PWA ecosystem (SvelteKit-based projects) — โปรเจกต์จำนวนมากที่ใช้ SvelteKit ต่อยอดจาก module นี้เพื่อทำ offline-first app

export ชื่อ build จาก $service-worker มีเนื้อหาอะไร?
ทำไมถึงตั้งชื่อ cache โดยใช้ export version?
event ใดเป็นสถานที่ที่เหมาะสมในการลบ stale cache จาก deployment ก่อนหน้า?
export ใดจาก $service-worker ที่แสดง path ของ HTML page ที่ prerender แล้ว?