# PWA Implementation in LunaTV: Offline Caching and Installation Benefits

> Discover PWA benefits in LunaTV. Learn how offline caching and installation enhance user experience for browsing TV guides and video content. Explore MoonTechLab/LunaTV.

- Repository: [MoonTechLab/LunaTV](https://github.com/MoonTechLab/LunaTV)
- Tags: benefits
- Published: 2026-09-08

---

**LunaTV leverages the `next-pwa` plugin to convert its Next.js application into an installable Progressive Web App that precaches static assets and API responses, enabling offline browsing of TV guides and video content.**

LunaTV is a React-based streaming interface built on the Next.js framework. Its Progressive Web App (PWA) implementation transforms the standard browser experience into a native-like application by utilizing service workers for offline resilience and dynamic manifest generation for home screen installation.

## Offline Caching and Network Resilience

The PWA implementation in LunaTV ensures functionality during network interruptions through strategic caching layers managed by a generated service worker.

**Precached Static Assets.** During the build process, `next-pwa` generates [`public/sw.js`](https://github.com/MoonTechLab/LunaTV/blob/main/public/sw.js) which precaches the application's HTML, CSS, JavaScript bundles, and static images. When users revisit LunaTV, these resources load instantly from the Cache Storage API rather than the network, eliminating latency on subsequent visits.

**Runtime API Caching.** The service worker intercepts fetch requests to `/api/*` endpoints and caches JSON responses. This allows users to view previously loaded video details and TV guide data even when connectivity drops. The configuration in [`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js) defines runtime caching strategies that balance freshness with availability.

**Network-First Fallback Strategy.** For critical streaming metadata, LunaTV implements a cache-fallback pattern. When a network request fails, the service worker automatically serves the most recent cached response, ensuring the UI remains functional and data remains accessible offline.

## Installable Experience via Web App Manifest

LunaTV transforms from a website into a standalone application through dynamic Web App Manifest generation and browser integration.

**Dynamic Manifest Generation.** The [`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js) file programmatically creates [`public/manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main/public/manifest.json) at build time, injecting environment-specific values like the site name and branding assets:

```javascript
// scripts/generate-manifest.js
const fs = require('fs');
const path = require('path');

const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'Luna TV';
const publicDir = path.resolve(__dirname, '..', 'public');

const manifestTemplate = {
  name: siteName,
  short_name: siteName,
  start_url: '/',
  display: 'standalone',
  background_color: '#000000',
  theme_color: '#ff6600',
  icons: [
    { src: '/icons/icon-192x192.png',   sizes: '192x192', type: 'image/png' },
    { src: '/icons/icon-512x512.png',   sizes: '512x512', type: 'image/png' }
  ]
};

fs.writeFileSync(
  path.join(publicDir, 'manifest.json'),
  JSON.stringify(manifestTemplate, null, 2)
);

```

**Native-Like Installation.** When browsers detect the manifest, they prompt users to "Add to Home Screen," creating a dedicated LunaTV icon alongside native applications. The `display: "standalone"` property removes browser chrome, providing a full-screen, distraction-free television interface that mimics native app behavior.

**Themed Launch Experience.** The manifest defines `background_color` and `theme_color` values that control the splash screen appearance during app startup, ensuring brand consistency from icon tap to full render.

## Technical Implementation Architecture

The PWA capabilities are integrated through three core technical components that work together during build and runtime.

### Configuring next-pwa in next.config.js

The PWA functionality is enabled via the `next-pwa` plugin configuration in the root configuration file:

```javascript
// next.config.js
module.exports = {
  pwa: {
    dest: "public",
    register: true,
    skipWaiting: true,
    // Runtime caching rules for API endpoints
    runtimeCaching: [
      {
        urlPattern: /^https:\/\/api\.lunatv\.com\/.*/,
        handler: 'NetworkFirst',
        options: {
          cacheName: 'api-cache',
          expiration: {
            maxEntries: 50,
            maxAgeSeconds: 24 * 60 * 60 // 24 hours
          }
        }
      }
    ]
  },
};

```

The `dest: "public"` setting outputs the service worker to [`public/sw.js`](https://github.com/MoonTechLab/LunaTV/blob/main/public/sw.js), making it available at the root scope. The `skipWaiting: true` flag ensures that updated service workers activate immediately, delivering the latest cached content to returning users without requiring a page refresh.

### Service Worker Registration

While `next-pwa` handles automatic registration, the implementation ensures compatibility through manual registration checks in the application entry point:

```tsx
// src/app/_app.tsx
import { useEffect } from 'react';

export default function MyApp({ Component, pageProps }) {
  useEffect(() => {
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/sw.js')
        .then(reg => console.log('SW registered', reg))
        .catch(err => console.error('SW registration failed', err));
    }
  }, []);
  return <Component {...pageProps} />;
}

```

### Optimized Data Fetching with Cache Headers

Application logic leverages the service worker cache through optimized fetch implementations:

```typescript
// src/lib/fetchVideoDetail.ts
export async function fetchVideoDetail(id: string) {
  const res = await fetch(`/api/video/${id}`, { cache: 'force-cache' });
  if (!res.ok) throw new Error('Network error');
  return res.json();
}

```

The `cache: 'force-cache'` directive works in conjunction with the service worker to prioritize cached responses, reducing bandwidth consumption and improving load times for frequently accessed content.

## Performance and SEO Benefits

**Progressive Enhancement.** The PWA layer operates as an enhancement rather than a requirement. On browsers lacking service worker support, LunaTV functions as a standard server-rendered Next.js application, ensuring universal accessibility while delivering advanced capabilities to modern browsers.

**Search Engine Visibility.** Because the underlying Next.js pages remain server-side rendered, search engine crawlers can index all video content and metadata. The PWA features improve user retention metrics—such as time on site and return visits—which indirectly support search ranking performance through enhanced engagement signals.

## Summary

- **Offline Resilience:** The service worker generated by `next-pwa` precaches static assets and runtime API responses, allowing LunaTV to function without network connectivity.
- **Native Installation:** The [`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js) utility creates a Web App Manifest that enables browser prompts for home screen installation and standalone full-screen display.
- **Instant Loading:** Cached resources eliminate network latency on repeat visits, delivering sub-second page transitions for returning users.
- **Progressive Architecture:** The implementation gracefully degrades on unsupported browsers while enhancing modern browsers with offline capabilities and push notification readiness.
- **SEO Preservation:** Server-side rendering remains intact, ensuring search engines can crawl content while users benefit from app-like performance.

## Frequently Asked Questions

### How does LunaTV handle API requests when the user is offline?

LunaTV's service worker, configured in [`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js), implements runtime caching strategies that store API responses in the browser's Cache Storage. When the network is unavailable, the service worker intercepts fetch requests to `/api/*` endpoints and returns the most recent cached JSON data, allowing users to continue viewing previously loaded TV guides and video details without interruption.

### What triggers the "Add to Home Screen" prompt in LunaTV?

The prompt appears when browsers detect the [`public/manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main/public/manifest.json) file generated by [`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js). This manifest includes required fields such as `name`, `short_name`, `start_url`, and `icons` (192x192 and 512x512 PNGs). The `display: "standalone"` setting informs browsers that LunaTV is optimized for installation, triggering the native prompt on supported devices.

### Where is the service worker file located in the LunaTV repository?

The service worker file is automatically generated at [`public/sw.js`](https://github.com/MoonTechLab/LunaTV/blob/main/public/sw.js) during the build process by the `next-pwa` plugin. This location ensures the service worker registers at the root scope (`/`), granting it control over all pages and API requests within the LunaTV domain. The configuration in [`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js) specifies `dest: "public"` to target this output directory.

### Can users receive updates to LunaTV while using the cached offline version?

Yes. The `skipWaiting: true` configuration in [`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js) ensures that updated service workers activate immediately upon installation, bypassing the waiting phase. This forces the new cache contents to replace outdated versions, guaranteeing that returning users receive the latest application code and content on their next visit, even when loading from the home screen icon.