# How to Configure PWA Capabilities in LunaTV: A Complete Setup Guide

> Configure PWA capabilities in LunaTV easily. Follow our guide to enable the next-pwa plugin, set environment variables, and ensure smooth manifest and icon routing for your progressive web app.

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

---

**Configure LunaTV as a Progressive Web App by enabling the `next-pwa` plugin in [`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js), setting the `NEXT_PUBLIC_SITE_NAME` environment variable, and ensuring the middleware skips authentication for [`/manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main//manifest.json) and `/icons/` routes.**

LunaTV, an open-source video aggregation platform by MoonTechLab, ships with built-in PWA support that transforms the Next.js application into an installable desktop and mobile experience. The implementation relies on three core components: a service worker generated by `next-pwa`, a dynamically created [`manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main/manifest.json), and middleware exceptions for static PWA assets. This guide walks through the exact configuration steps based on the source code in the MoonTechLab/LunaTV repository.

## Configure the next-pwa Plugin

The PWA functionality centers on the `next-pwa` package, configured in [[`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js)](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js) (lines 72‑79). This plugin injects a service worker that caches assets and enables offline capabilities.

```javascript
const withPWA = require('next-pwa')({
  dest: 'public',               // Service worker output directory
  disable: process.env.NODE_ENV === 'development',
  register: true,               // Auto-register on the client
  skipWaiting: true,            // Activate new versions immediately
});

module.exports = withPWA(nextConfig);

```

**Key parameters:**
- **`dest: 'public'`** – Writes the service worker to the `public/` directory so Next.js serves it at the root.
- **`register: true`** – Automatically registers the service worker when the app loads in the browser.
- **`skipWaiting: true`** – Forces new service worker versions to activate immediately, ensuring users always get the latest cached shell.

## Set Environment Variables for Branding

LunaTV generates the PWA manifest dynamically using the `NEXT_PUBLIC_SITE_NAME` environment variable. Define this in your `.env` file to customize the app name that appears on the home screen.

```env
NEXT_PUBLIC_SITE_NAME="My Luna TV Brand"

```

If this variable is undefined, the [[`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js)](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js) script falls back to `"MoonTV"`. This value populates both the `name` and `short_name` fields in the final manifest.

## Generate the Dynamic Manifest

Unlike static manifest files, LunaTV creates [`public/manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main/public/manifest.json) at build time via [[`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js)](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js). The script reads `NEXT_PUBLIC_SITE_NAME` and writes a JSON file with PWA metadata.

```javascript
// scripts/generate-manifest.js (excerpt)
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'MoonTV';
const manifestTemplate = {
  name: siteName,
  short_name: siteName,
  description: '影视聚合',
  start_url: '/',
  scope: '/',
  display: 'standalone',
  background_color: '#000000',
  'apple-mobile-web-app-capable': 'yes',
  'apple-mobile-web-app-status-bar-style': 'black',
  icons: [ /* icon definitions */ ],
};

fs.writeFileSync(manifestPath, JSON.stringify(manifestTemplate, null, 2));

```

**Automation tip:** Add a `postinstall` hook to [`package.json`](https://github.com/MoonTechLab/LunaTV/blob/main/package.json) so the manifest regenerates after every install:

```json
{
  "scripts": {
    "postinstall": "node scripts/generate-manifest.js",
    "build": "next build"
  }
}

```

## Provide Icon Assets

The manifest references PNG icons located in `public/icons/`. LunaTV requires four specific sizes for full PWA compatibility:

- `icon-192x192.png`
- `icon-256x256.png`
- `icon-384x384.png`
- `icon-512x512.png`

Replace these files with your own branded assets while maintaining the exact pixel dimensions. The [[`generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/generate-manifest.js)](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js) script automatically references these paths when constructing the `icons` array.

## Exclude Static Routes from Authentication

LunaTV uses Next.js middleware for authentication. To prevent the browser from being redirected when fetching PWA resources, [[`src/middleware.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/middleware.ts)](https://github.com/MoonTechLab/LunaTV/blob/main/src/middleware.ts) explicitly skips [`/manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main//manifest.json) and `/icons/`:

```typescript
const skipPaths = [
  '/manifest.json',
  '/icons/',
  // ...other static assets
];

```

This ensures unauthenticated browsers can still download the manifest and icons required for the "Add to Home Screen" prompt.

## Customizing the PWA Manifest

To extend the manifest with additional fields—such as `theme_color` or custom categories—modify the template object in [`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js):

```javascript
const manifestTemplate = {
  name: siteName,
  short_name: siteName,
  description: 'My custom video collection',
  theme_color: '#1a202c',   // Added custom theme color
  background_color: '#000000',
  display: 'standalone',
  // ...existing fields
};

```

After editing, run `node scripts/generate-manifest.js` to regenerate [`public/manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main/public/manifest.json), or trigger the `postinstall` script.

## Verifying Your PWA Setup

Once deployed, verify the configuration using Chrome DevTools:

1. Open the site and press **F12** to open DevTools.
2. Navigate to **Application > Service Workers**.
3. Confirm a worker is registered with scope `"/"` and status **"Running"**.
4. Check **Application > Manifest** to verify the `name`, `icons`, and `display` mode reflect your configuration.

Users on supported browsers can now install LunaTV via the "Add to Home Screen" prompt, receiving an offline-capable app that launches in standalone mode without browser chrome.

## Summary

- **Service Worker**: Configured via `next-pwa` in [`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js) (lines 72‑79) with `dest: 'public'` and `register: true`.
- **Dynamic Manifest**: Generated by [`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js) using `NEXT_PUBLIC_SITE_NAME`, falling back to "MoonTV".
- **Icon Requirements**: Place four PNG files (192×192 through 512×512) in `public/icons/`.
- **Middleware Exclusions**: [`src/middleware.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/middleware.ts) must skip [`/manifest.json`](https://github.com/MoonTechLab/LunaTV/blob/main//manifest.json) and `/icons/` to serve PWA assets without authentication.
- **Development Toggle**: PWA features auto-disable in development via `disable: process.env.NODE_ENV === 'development'`.

## Frequently Asked Questions

### What does the service worker do in LunaTV?

The service worker, generated by `next-pwa` and placed in `public/`, caches the application's shell and assets. This enables offline functionality and ensures the app loads instantly on repeat visits by serving cached content first, as configured with `skipWaiting: true` for immediate activation.

### Why is the manifest.json file generated dynamically?

LunaTV uses a dynamic manifest to support customizable branding through the `NEXT_PUBLIC_SITE_NAME` environment variable. The [`scripts/generate-manifest.js`](https://github.com/MoonTechLab/LunaTV/blob/main/scripts/generate-manifest.js) script runs during the build process (or via `postinstall`) to inject the site name into the `name` and `short_name` fields, allowing multiple deployments from the same codebase with distinct identities.

### Can I disable PWA features in development?

Yes. The `next-pwa` configuration in [`next.config.js`](https://github.com/MoonTechLab/LunaTV/blob/main/next.config.js) sets `disable: process.env.NODE_ENV === 'development'`, which prevents service worker registration and caching during local development. This ensures you always see fresh code changes without needing to unregister workers manually.

### What icon sizes are required for LunaTV's PWA?

LunaTV expects four icon sizes in `public/icons/`: 192×192 pixels, 256×256 pixels, 384×384 pixels, and 512×512 pixels. These dimensions cover the requirements for Android, iOS, and desktop PWA installations, ensuring crisp display across all device home screens and app switchers.