Transform Next.js applications into Progressive Web Apps with offline support, push notifications, and installability.
# PWA Implementation for Google Antigravity
Progressive Web Apps combine the best of web and native applications. This guide covers PWA implementation optimized for Google Antigravity and Next.js development.
## Service Worker Configuration
Set up a comprehensive service worker:
```typescript
// public/sw.js
const CACHE_NAME = "antigravity-pwa-v1";
const STATIC_ASSETS = [
"/",
"/offline",
"/manifest.json",
"/icons/icon-192.png",
"/icons/icon-512.png",
];
// Install event - cache static assets
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log("Caching static assets");
return cache.addAll(STATIC_ASSETS);
})
);
self.skipWaiting();
});
// Activate event - clean old caches
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => name !== CACHE_NAME)
.map((name) => caches.delete(name))
);
})
);
self.clients.claim();
});
// Fetch event - network first with cache fallback
self.addEventListener("fetch", (event) => {
const { request } = event;
const url = new URL(request.url);
// Skip non-GET requests
if (request.method !== "GET") return;
// Skip cross-origin requests
if (url.origin !== self.location.origin) return;
// API requests - network only
if (url.pathname.startsWith("/api/")) {
event.respondWith(fetch(request));
return;
}
// Static assets - cache first
if (url.pathname.match(/\.(js|css|png|jpg|jpeg|svg|woff2)$/)) {
event.respondWith(
caches.match(request).then((cached) => {
return cached || fetch(request).then((response) => {
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(request, clone));
return response;
});
})
);
return;
}
// HTML pages - network first with offline fallback
event.respondWith(
fetch(request)
.then((response) => {
const clone = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(request, clone));
return response;
})
.catch(() => {
return caches.match(request).then((cached) => {
return cached || caches.match("/offline");
});
})
);
});
// Push notification handler
self.addEventListener("push", (event) => {
const data = event.data?.json() ?? {};
const title = data.title || "New Notification";
const options = {
body: data.body,
icon: "/icons/icon-192.png",
badge: "/icons/badge-72.png",
vibrate: [100, 50, 100],
data: { url: data.url || "/" },
actions: data.actions || [],
};
event.waitUntil(self.registration.showNotification(title, options));
});
// Notification click handler
self.addEventListener("notificationclick", (event) => {
event.notification.close();
const url = event.notification.data.url;
event.waitUntil(
clients.matchAll({ type: "window" }).then((windowClients) => {
for (const client of windowClients) {
if (client.url === url && "focus" in client) {
return client.focus();
}
}
return clients.openWindow(url);
})
);
});
```
## Web App Manifest
Configure comprehensive manifest:
```json
// public/manifest.json
{
"name": "Antigravity AI Directory",
"short_name": "Antigravity",
"description": "The #1 directory for Google Antigravity prompts and MCP servers",
"start_url": "/",
"display": "standalone",
"background_color": "#000000",
"theme_color": "#6366f1",
"orientation": "portrait-primary",
"scope": "/",
"icons": [
{
"src": "/icons/icon-72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
],
"screenshots": [
{
"src": "/screenshots/home.png",
"sizes": "1280x720",
"type": "image/png",
"form_factor": "wide"
},
{
"src": "/screenshots/mobile.png",
"sizes": "750x1334",
"type": "image/png",
"form_factor": "narrow"
}
],
"categories": ["developer tools", "productivity"],
"shortcuts": [
{
"name": "Browse Prompts",
"url": "/prompts",
"icons": [{ "src": "/icons/prompts.png", "sizes": "96x96" }]
},
{
"name": "MCP Servers",
"url": "/mcp",
"icons": [{ "src": "/icons/mcp.png", "sizes": "96x96" }]
}
]
}
```
## Service Worker Registration
Register and manage the service worker:
```typescript
// lib/pwa/register.ts
export async function registerServiceWorker() {
if (typeof window === "undefined" || !("serviceWorker" in navigator)) {
return null;
}
try {
const registration = await navigator.serviceWorker.register("/sw.js", {
scope: "/",
updateViaCache: "none",
});
// Check for updates periodically
setInterval(() => {
registration.update();
}, 60 * 60 * 1000); // Every hour
// Handle updates
registration.addEventListener("updatefound", () => {
const newWorker = registration.installing;
if (!newWorker) return;
newWorker.addEventListener("statechange", () => {
if (newWorker.state === "installed" && navigator.serviceWorker.controller) {
// New version available
dispatchEvent(new CustomEvent("pwa-update-available"));
}
});
});
return registration;
} catch (error) {
console.error("Service worker registration failed:", error);
return null;
}
}
// components/PWAProvider.tsx
"use client";
import { useEffect, useState } from "react";
import { registerServiceWorker } from "@/lib/pwa/register";
export function PWAProvider({ children }: { children: React.ReactNode }) {
const [updateAvailable, setUpdateAvailable] = useState(false);
useEffect(() => {
registerServiceWorker();
const handleUpdate = () => setUpdateAvailable(true);
window.addEventListener("pwa-update-available", handleUpdate);
return () => window.removeEventListener("pwa-update-available", handleUpdate);
}, []);
const handleReload = () => {
window.location.reload();
};
return (
<>
{children}
{updateAvailable && (
<div className="fixed bottom-4 right-4 bg-primary text-white p-4 rounded-lg shadow-lg">
<p>A new version is available!</p>
<button onClick={handleReload} className="mt-2 underline">
Refresh to update
</button>
</div>
)}
</>
);
}
```
## Best Practices
When implementing PWAs in Antigravity projects, cache critical assets during install, use network-first for dynamic content, implement offline fallback pages, test on various devices and networks, use Lighthouse for PWA audits, implement background sync for offline actions, and provide clear install prompts for users.This PWA prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their pwa implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For PWA projects, consider mentioning your framework version, coding style, and any specific libraries you're using.