Claude Code से PWA बनाना: Manifest, Service Worker और Offline Cache
Claude Code से PWA बनाने की व्यावहारिक गाइड: manifest, icons, Service Worker, offline fallback, cache और validation.
PWA, यानी Progressive Web App, ऐसा वेब ऐप है जिसे उपयोगकर्ता इंस्टॉल किए गए ऐप की तरह इस्तेमाल कर सकता है। इसमें ऐप का नाम और icon होता है, यह standalone window में खुल सकता है, जरूरी assets cache कर सकता है, और network न होने पर खाली error page के बजाय उपयोगी offline page दिखा सकता है।
लेकिन PWA सिर्फ manifest.webmanifest जोड़ने से पूरी नहीं होती। आपको सही icon sizes, Service Worker, offline fallback, cache strategy, installability checks, और Chrome DevTools/Lighthouse validation भी चाहिए। एक icon path 404 हो जाए या पुराना HTML cache में अटक जाए, तो production में अजीब bug दिख सकते हैं।
यह लेख Claude Code की मदद से beginner-friendly PWA implementation दिखाता है। अगर आप Claude Code में नए हैं, तो पहले Claude Code getting started guide पढ़ें। Official reference के लिए web.dev Learn PWA, MDN installable PWA guide, MDN PWA best practices, Chrome install criteria update, और Claude Code docs देखें।
PWA की बुनियादी संरचना
PWA कई छोटी files का संयोजन है। HTML manifest को link करता है, app entry point Service Worker register करता है, और Service Worker अपने scope में आने वाली requests पर network या cache strategy लागू करता है।
User site खोलता है
-> index.html manifest.webmanifest link करता है
-> register-sw.js /sw.js register करता है
-> sw.js app shell cache करता है
-> fetch event resource type के आधार पर strategy चुनता है
-> offline navigation को offline.html मिलता है
Implementation से पहले तीन बातें तय करें।
| निर्णय | उदाहरण | क्यों जरूरी |
|---|---|---|
| Start URL और scope | / या /app/ | mismatch होने पर Service Worker page control नहीं करेगा |
| Cache resources | HTML, CSS, JS, images, offline.html | गलत cache से stale content या 404 रह सकते हैं |
| Offline behavior | offline page, recent page, API error | user को साफ state मिलनी चाहिए |
Blog, course library या छोटा dashboard हो तो conservative setup से शुरू करें: HTML navigation के लिए Network First, images/icons के लिए Cache First, और CSS/JS/fonts के लिए Stale While Revalidate। Cache design पर और detail चाहिए तो Claude Code caching strategies भी उपयोगी है।
Claude Code को देने वाला prompt
Claude Code को सिर्फ “PWA बना दो” कहना पर्याप्त नहीं है। Files, rules और validation criteria साफ लिखें।
इस existing Vite/React app को PWA में बदलें।
Requirements:
- public/manifest.webmanifest add करें
- 192x192, 512x512 और maskable 512x512 PNG icons refer करें
- public/offline.html add करें
- public/sw.js Service Worker add करें
- src/register-sw.js से Service Worker register करें
- HTML navigation के लिए Network First
- images के लिए Cache First
- CSS, JS और fonts के लिए Stale While Revalidate
- POST और cross-origin requests cache न करें
- नई Service Worker version मिलने पर refresh notice दिखाएं
- अंत में DevTools और Lighthouse checklist दें
Constraints:
- installability दिखाने के लिए empty fetch handler न जोड़ें
- हर changed file explain करें
- production base path पर depend करने वाली paths बताएं
Masa ने एक छोटे Vite course landing page पर test किया तो code generation जल्दी हुआ, पर पहला bug start_url और scope mismatch था। Prompt में ये assumptions लिखवाने से Claude Code बेहतर review करता है।
Manifest और icons
public/manifest.webmanifest बनाएं। name full app name है, short_name small spaces के लिए है, start_url installed app का पहला URL है, और scope control की सीमा बताता है।
{
"id": "/",
"name": "ClaudeCodeLab PWA Demo",
"short_name": "CCLab",
"description": "Claude Code से बना offline-ready PWA demo",
"start_url": "/?source=pwa",
"scope": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#0f766e",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "/icons/icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}
HTML head में manifest link करें।
<link rel="manifest" href="/manifest.webmanifest" />
<meta name="theme-color" content="#0f766e" />
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png" />
Icon files सचमुच मौजूद होने चाहिए। कम से कम 192x192 और 512x512 PNG रखें। Maskable icon में logo के आसपास safe padding रखें, वरना launcher अलग shape में crop कर सकता है। Claude Code paths add कर दे, फिर भी browser में icon URL खोलकर 200 response confirm करें।
Service Worker code
public/sw.js में यह starting implementation रखें। यह app shell precache करता है, पुरानी caches हटाता है, और सिर्फ same-origin GET requests संभालता है।
const VERSION = "2026-06-02";
const STATIC_CACHE = `static-${VERSION}`;
const RUNTIME_CACHE = `runtime-${VERSION}`;
const APP_SHELL = [
"/",
"/offline.html",
"/manifest.webmanifest",
"/icons/icon-192.png",
"/icons/icon-512.png",
"/icons/icon-maskable-512.png"
];
self.addEventListener("install", (event) => {
event.waitUntil(
caches
.open(STATIC_CACHE)
.then((cache) => cache.addAll(APP_SHELL))
.then(() => self.skipWaiting())
);
});
self.addEventListener("activate", (event) => {
const allowedCaches = [STATIC_CACHE, RUNTIME_CACHE];
event.waitUntil(
caches
.keys()
.then((keys) =>
Promise.all(
keys
.filter((key) => !allowedCaches.includes(key))
.map((key) => caches.delete(key))
)
)
.then(() => self.clients.claim())
);
});
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(networkFirstPage(request));
return;
}
if (request.destination === "image") {
event.respondWith(cacheFirst(request));
return;
}
if (["style", "script", "font"].includes(request.destination)) {
event.respondWith(staleWhileRevalidate(request));
}
});
async function networkFirstPage(request) {
const cache = await caches.open(RUNTIME_CACHE);
try {
const response = await fetch(request);
if (response.ok) await cache.put(request, response.clone());
return response;
} catch {
const cached = await cache.match(request);
return cached || (await caches.match("/offline.html")) || new Response("Offline", { status: 503 });
}
}
async function cacheFirst(request) {
const cached = await caches.match(request);
if (cached) return cached;
const response = await fetch(request);
if (response.ok) {
const cache = await caches.open(RUNTIME_CACHE);
await cache.put(request, response.clone());
}
return response;
}
async function staleWhileRevalidate(request) {
const cache = await caches.open(RUNTIME_CACHE);
const cached = await cache.match(request);
const networkPromise = fetch(request)
.then((response) => {
if (response.ok) cache.put(request, response.clone());
return response;
})
.catch(() => undefined);
if (cached) return cached;
return (await networkPromise) || new Response("Network error", { status: 504 });
}
यह code POST, cross-origin और private API responses cache नहीं करता। Login, payment, cart, permissions और inventory जैसी चीजों को generic runtime cache में डालना risky है। Cache speed feature है, लेकिन वह persistent storage भी है।
Offline page और registration
public/offline.html छोटा और independent रखें।
<!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>Network वापस आने पर page reload करें। हाल में खोले गए pages कभी-कभी उपलब्ध रह सकते हैं।</p>
<p><a href="/">Home पर लौटें</a></p>
</main>
</body>
</html>
src/register-sw.js से Service Worker register करें।
export async function registerServiceWorker() {
if (!("serviceWorker" in navigator)) return;
window.addEventListener("load", async () => {
try {
const registration = await navigator.serviceWorker.register("/sw.js", {
scope: "/"
});
registration.addEventListener("updatefound", () => {
const worker = registration.installing;
if (!worker) return;
worker.addEventListener("statechange", () => {
if (worker.state === "installed" && navigator.serviceWorker.controller) {
document.querySelector("[data-refresh-app]")?.removeAttribute("hidden");
}
});
});
} catch (error) {
console.error("Service Worker registration failed:", error);
}
});
}
Entry file में एक बार import करें।
import { registerServiceWorker } from "./register-sw.js";
registerServiceWorker();
Update notice जरूरी है, क्योंकि नया Service Worker तुरंत हर tab को control नहीं करता। लंबे समय तक खुले tabs में old worker रह सकता है।
Install button और validation
कुछ Chromium browsers beforeinstallprompt event देते हैं। इसे progressive enhancement की तरह use करें।
let deferredPrompt = null;
window.addEventListener("beforeinstallprompt", (event) => {
event.preventDefault();
deferredPrompt = event;
document.querySelector("[data-install-app]")?.removeAttribute("hidden");
});
document.querySelector("[data-install-app]")?.addEventListener("click", async () => {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const choice = await deferredPrompt.userChoice;
console.info("Install result:", choice.outcome);
deferredPrompt = null;
});
Validation में पुराने PWA score पर निर्भर न रहें। DevTools Application panel में Manifest, Service Worker, Cache Storage और Offline behavior देखें। Lighthouse को performance, accessibility, best practices और SEO के लिए चलाएं।
npm run build
npx serve dist -l 4173
npx lighthouse http://localhost:4173 --view --only-categories=performance,accessibility,best-practices,seo
| Check | Location | Pass condition |
|---|---|---|
| Manifest | Application > Manifest | name, start_url और icons बिना error |
| Service Worker | Application > Service Workers | /sw.js activated |
| Offline reload | Network Offline करके reload | offline.html या recent page दिखे |
| Cache Storage | Application > Cache Storage | static/runtime caches सही हों |
| Lighthouse | Report | performance, SEO, accessibility degrade न हों |
Use cases, CTA और pitfalls
PWA उन products में सबसे ज्यादा उपयोगी है जहां repeat usage है: course library, technical blog, internal dashboard, event guide, या image-heavy commerce page। Course site में user commute के दौरान पढ़ सकता है। Dashboard में daily launch आसान होता है। Event guide में खराब network के बीच schedule दिखता है। Commerce में recent browsing और images तेज लगते हैं।
Monetization के लिए सिर्फ “installable app” न बेचें। Install clicks, offline fallback hits, returning users, reading completion और product CTA clicks measure करें। ClaudeCodeLab के templates और prompt packs के लिए product library देखें। Team project में cache review, deployment path validation और analytics events भी scope में रखें।
Common pitfalls हैं: scope और start_url mismatch; HTML को Cache First करना; private API data cache करना; icon path 404; और debugging के समय old Service Worker unregister न करना। Issue आए तो Application panel में Unregister करें, Cache Storage clear करें, और first visit flow दोबारा test करें।
Tested result
Masa ने छोटे Vite course landing page में यह pattern test किया। Claude Code ने manifest, offline page और registration जल्दी बना दिए, पर verification में ज्यादा समय लगा: icon URLs, Offline reload, और new deployment के बाद old caches clear करना। Practical conclusion यह है कि पहले minimal offline fallback ship करें, फिर सिर्फ उन pages/assets को cache करें जिनसे returning users को सच में फायदा हो।
मुफ़्त PDF: Claude Code cheatsheet
Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.
हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.
लेखक के बारे में
Masa
Claude Code workflow और team adoption पर काम करने वाला engineer.
संबंधित लेख
Claude Code Obsidian to CLAUDE.md workflow: context बार-बार न समझाएं
Obsidian notes को CLAUDE.md operating notes में बदलकर Claude Code sessions को resume करना आसान बनाएं.
Claude Code Revenue CTA Routing: article से PDF, Gumroad और consultation तक
Reader intent के आधार पर free PDF, Gumroad products और consultation तक CTA route करने वाला workflow.
Claude Code टीम हैंडऑफ नियम: review proof, permissions, rollback और revenue path
Claude Code टीम काम के लिए evidence, permission rules, rollback, free PDF, Gumroad और consultation path वाला handoff.