Claude Code से Service Worker लागू करें: cache, update और offline UX
Service Worker, cache invalidation, update flow, offline UX और runnable Claude Code examples की practical guide.
Service Worker PWA और offline support के लिए बहुत काम की browser feature है, लेकिन गलत तरीके से लगाई जाए तो production bug बन जाती है। अगर आप Claude Code से बस “cache add कर दो” कहेंगे, तो app पुराना HTML दिखा सकता है, private account data browser में रख सकता है, या deploy के बाद भी नई version नहीं दिखा सकता।
Service Worker को browser और server के बीच छोटा proxy समझें। Request निकलने से पहले यह तय कर सकता है कि response network से आए, Cache API से आए, या offline fallback page दिखाया जाए। इस guide में Claude Code को task देने से पहले की decisions, copy-paste चलने वाला minimal code, cache invalidation, update lifecycle, offline UX और common failure cases शामिल हैं।
Implementation करते समय official references साथ रखें: MDN Service Worker API, web.dev service worker guidance, web.dev caching guidance, और Chrome Workbox docs. Related ClaudeCodeLab articles: PWA guide, caching strategies, और IndexedDB guide.
Service Worker क्या करता है
Service Worker page के बाहर चलने वाला JavaScript है। यह DOM को directly नहीं छू सकता, इसलिए button, form या React state नहीं बदलता। इसकी ताकत network requests को intercept करने में है: किस request को network first भेजना है, किसे cache से लौटाना है, और offline में कौन सा fallback दिखाना है।
Normal page script tab बंद होते ही खत्म हो जाता है। Service Worker event-driven होता है; browser उसे install, activate, fetch, push और कुछ cases में background sync events पर जगाता है। शुरुआत के लिए fetch, Cache API और update lifecycle सही रखना सबसे जरूरी है।
sequenceDiagram
participant User as User
participant Page as Page
participant SW as Service Worker
participant Cache as Cache API
participant Net as Server
User->>Page: Site खोलता है
Page->>SW: /sw.js register करता है
Page->>SW: fetch request भेजता है
SW->>Cache: cache check करता है
alt Cached
Cache-->>SW: stored response
else Not cached
SW->>Net: fresh response मांगता है
Net-->>SW: new response
end
SW-->>Page: render के लिए response
यह performance magic नहीं, traffic control है। Quality इस बात पर निर्भर करती है कि क्या store होगा, कब delete होगा, और network fail होने पर user को क्या दिखेगा।
Practical use cases
| Use case | फायदा | सावधानी |
|---|---|---|
| Documentation या blog | Article, CSS, image और font repeat visit पर जल्दी दिखते हैं | HTML ज्यादा देर cache हुआ तो correction नहीं दिखेगा |
| SaaS dashboard | Weak network में भी navigation shell दिख सकता है | Billing, account और private responses cache न करें |
| Field form app | Offline में drafts और pending jobs बचते हैं | POST को Cache API में नहीं, IndexedDB queue में रखें |
| Ecommerce या media catalog | Thumbnails और static assets बार-बार download नहीं होते | Price, stock और protected images की freshness manage करें |
Masa ने small learning site पर यह pattern test किया। Images और fonts cache करने से repeat visit साफ तेज लगी। लेकिन article HTML को Cache First करने पर typo fix users तक देर से पहुँचा। Claude Code को “सब cache कर दो” नहीं, बल्कि “यह cache करो, इतने time तक, और यह exclude करो” बताना चाहिए।
Claude Code prompt
Prompt में requirements, ban list और verification साथ लिखें।
Existing Vite app में Service Worker add करें।
Requirements:
- /sw.js को public root में रखें और scope / रखें
- केवल GET static assets cache करें
- HTML navigation के लिए Network First use करें
- Offline navigation fail हो तो /offline.html return करें
- API, POST, auth pages और other origins cache न करें
- Cache name में date या version रखें
- activate में old caches delete करें
- New worker waiting हो तो user को reload prompt दिखाएँ
Verification:
- Chrome DevTools > Application > Service Workers में registration देखें
- Network को Offline करके /offline.html confirm करें
- CACHE_VERSION बदलकर old cache deletion confirm करें
Exclusions जरूरी हैं। API या private page का गलत cache UI bug नहीं, data bug बन सकता है।
Copy-paste minimal implementation
इन चार files को sw-demo जैसे empty folder में रखें और local server चलाएँ। Service Worker HTTPS या localhost पर ही चलता है; HTML double-click करने से registration नहीं होगा।
python -m http.server 5173
Browser में http://localhost:5173 खोलें।
<!-- index.html -->
<!doctype html>
<html lang="hi">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Service Worker Demo</title>
<style>
body {
font-family: system-ui, sans-serif;
margin: 2rem;
line-height: 1.7;
}
button {
padding: 0.7rem 1rem;
}
</style>
</head>
<body>
<h1>Service Worker Demo</h1>
<p id="status">Registration का इंतजार है।</p>
<button type="button" onclick="location.reload()">Reload</button>
<script src="/register-sw.js"></script>
</body>
</html>
// register-sw.js
const status = document.querySelector("#status");
let reloadRequested = false;
let updatePromptShown = false;
function setStatus(message) {
if (status) status.textContent = message;
}
function askToReload(worker) {
if (updatePromptShown) return;
updatePromptShown = true;
const ok = window.confirm("New version available है। अभी reload करें?");
if (ok) {
reloadRequested = true;
worker.postMessage({ type: "SKIP_WAITING" });
}
}
async function registerServiceWorker() {
if (!("serviceWorker" in navigator)) {
setStatus("यह browser Service Worker support नहीं करता।");
return;
}
try {
const registration = await navigator.serviceWorker.register("/sw.js", {
scope: "/",
});
setStatus(`Service Worker registered: ${registration.scope}`);
if (registration.waiting && navigator.serviceWorker.controller) {
askToReload(registration.waiting);
}
registration.addEventListener("updatefound", () => {
const worker = registration.installing;
if (!worker) return;
worker.addEventListener("statechange", () => {
const hasOldController = Boolean(navigator.serviceWorker.controller);
if (worker.state === "installed" && hasOldController) {
askToReload(worker);
}
});
});
} catch (error) {
console.error(error);
setStatus("Service Worker registration fail हुआ।");
}
}
navigator.serviceWorker?.addEventListener("controllerchange", () => {
if (!reloadRequested) return;
window.location.reload();
});
registerServiceWorker();
// sw.js
const CACHE_VERSION = "2026-06-02-v1";
const CACHE_PREFIX = "claude-sw-demo";
const CACHE_NAME = `${CACHE_PREFIX}-${CACHE_VERSION}`;
const APP_SHELL = [
"/",
"/index.html",
"/offline.html",
"/register-sw.js",
];
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL)),
);
});
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((names) =>
Promise.all(
names
.filter((name) => name.startsWith(CACHE_PREFIX))
.filter((name) => name !== CACHE_NAME)
.map((name) => caches.delete(name)),
),
),
);
self.clients.claim();
});
self.addEventListener("message", (event) => {
if (event.data?.type === "SKIP_WAITING") {
self.skipWaiting();
}
});
self.addEventListener("fetch", (event) => {
const { request } = event;
if (request.method !== "GET") return;
const url = new URL(request.url);
if (url.origin !== self.location.origin) return;
if (request.mode === "navigate") {
event.respondWith(networkFirstNavigation(request));
return;
}
if (["style", "script", "font", "image"].includes(request.destination)) {
event.respondWith(staleWhileRevalidate(request));
}
});
async function networkFirstNavigation(request) {
const cache = await caches.open(CACHE_NAME);
try {
const response = await fetch(request);
if (response.ok) cache.put(request, response.clone());
return response;
} catch {
return (
(await cache.match(request)) ||
(await cache.match("/offline.html")) ||
new Response("Offline", { status: 503 })
);
}
}
async function staleWhileRevalidate(request) {
const cache = await caches.open(CACHE_NAME);
const cached = await cache.match(request);
const fetched = fetch(request)
.then((response) => {
if (response.ok) cache.put(request, response.clone());
return response;
})
.catch(() => cached || new Response("Offline", { status: 503 }));
return cached || fetched;
}
<!-- offline.html -->
<!doctype html>
<html lang="hi">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>आप offline हैं</title>
</head>
<body>
<main>
<h1>आप offline हैं</h1>
<p>Connection वापस आने पर page reload करें।</p>
<button type="button" onclick="location.reload()">Try again</button>
</main>
</body>
</html>
यह example navigation के लिए Network First और CSS, JavaScript, fonts, images के लिए Stale While Revalidate use करता है। Network First पहले server पूछता है और fail होने पर cache या offline.html पर लौटता है। Stale While Revalidate cached response तुरंत देता है और background में refresh करता है। News, price, inventory या authenticated screens पर इसे बिना सोचे apply न करें।
Update और cache invalidation
सबसे common issue update lifecycle है। sw.js बदलने पर browser new worker install करता है। अगर old page खुला है, तो new worker अक्सर waiting state में रुकता है। ऊपर का registration code यह state detect करता है, user से पूछता है, और approval मिलने पर SKIP_WAITING भेजता है।
Worker फिर self.skipWaiting() call करता है, activate होता है, old caches delete करता है और clients claim करता है। यह flow न हो तो user deploy के बाद भी old app-cache-v1 इस्तेमाल कर सकता है।
Cache name में date, release number या commit ID रखें। Build hashed files बनाता है तो precache list build output से match होनी चाहिए। Manual list fragile लगे तो Workbox helpful है, लेकिन Workbox भी यह decide नहीं करता कि business data cache करना safe है या नहीं।
Offline UX
Offline support सिर्फ Cache API response नहीं है। User को पता होना चाहिए कि काम saved है, sync का wait कर रहा है, या failed है। Forms में POST को Cache API में store न करें। Page side पर drafts या pending jobs IndexedDB में रखें और online वापस आने पर retry करें। Background Sync useful है, लेकिन browser support अलग-अलग है; critical flow में online event और visible retry button रखें।
Claude Code prompt में offline text, retry button, draft states और sync-failure messages शामिल करें। Field app में कम से कम “sent”, “saved on this device” और “sync failed” states अलग होने चाहिए।
Common failure cases
पहला failure scope mismatch है। /app/sw.js default रूप से /app/ control करता है, पूरा site नहीं। Full-site control चाहिए तो /sw.js use करें और scope / रखें।
दूसरा failure cache.addAll() में 404 है। List में एक missing URL भी हो तो पूरा install fail हो जाता है। Claude Code files add करे तो DevTools Application और Cache Storage जरूर देखें।
तीसरा failure private data है। /api/me, billing pages, admin HTML या user-specific JSON cache न करें जब तक deletion strategy बहुत clear न हो। Browser cache user device पर storage ही है।
चौथा failure update UX skip करना है। Old worker old JS और CSS पकड़े रह सकता है। Cache names version करें, activate में delete करें, और worker waiting हो तो user को reload का option दें।
अंत में, Service Worker permanent storage नहीं है। Browser space कम होने पर caches evict कर सकता है। Cross-origin opaque responses debug करना कठिन है। DOM access नहीं है। HTTPS या localhost जरूरी है। Real workflow test किए बिना “complete offline” promise न करें।
Summary और CTA
Service Worker repeat visits, offline behavior और PWA quality बेहतर करता है। Safe path यह है कि Claude Code से files edit कराने से पहले cache ownership, update lifecycle, private data rules और offline screens तय हों।
ClaudeCodeLab PWA conversion, cache design, offline forms, Workbox migration और Claude Code implementation review में मदद करता है। अगर site तेज करनी है लेकिन stale या private data serve नहीं करना, तो Claude Code training और consulting से शुरू करें।
इस minimal setup को local Chrome में test करने पर first load के बाद Application panel में claude-sw-demo-2026-06-02-v1 दिखता है। Network को Offline करके reload करने पर offline.html दिखता है। CACHE_VERSION बदलने पर old caches activate में delete होते हैं, इसलिए यह release verification के लिए अच्छा starting point है।
मुफ़्त PDF: Claude Code cheatsheet
Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.
हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.
लेखक के बारे में
Masa
Claude Code workflow और team adoption पर काम करने वाला engineer.
संबंधित लेख
Claude Code permission safety ladder: access धीरे-धीरे बढ़ाएं
read-only से limited edits, proof commands और deploy checks तक permission बढ़ाने की सुरक्षित ladder.
Claude Code Small PR Proof Pack: छोटे PR को review-ready बनाना
Claude Code PR के लिए diff, checks, public URL, CTA path और rollback वाला practical proof pack.
Claude Code Review Gate Before Commit: diff, test, public URL और CTA जांच
Claude Code से commit से पहले review gate बनाएं: diff, build, public URL, Gumroad, consultation, tests और unrelated files।