How to Configure PWA Capabilities in LunaTV: A Complete Setup Guide
Configure LunaTV as a Progressive Web App by enabling the next-pwa plugin in next.config.js, setting the NEXT_PUBLIC_SITE_NAME environment variable, and ensuring the middleware skips authentication for /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, 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) (lines 72‑79). This plugin injects a service worker that caches assets and enables offline capabilities.
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 thepublic/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.
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) 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 at build time via [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.
// 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 so the manifest regenerates after every install:
{
"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.pngicon-256x256.pngicon-384x384.pngicon-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/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) explicitly skips /manifest.json and /icons/:
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:
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, or trigger the postinstall script.
Verifying Your PWA Setup
Once deployed, verify the configuration using Chrome DevTools:
- Open the site and press F12 to open DevTools.
- Navigate to Application > Service Workers.
- Confirm a worker is registered with scope
"/"and status "Running". - Check Application > Manifest to verify the
name,icons, anddisplaymode 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-pwainnext.config.js(lines 72‑79) withdest: 'public'andregister: true. - Dynamic Manifest: Generated by
scripts/generate-manifest.jsusingNEXT_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.tsmust skip/manifest.jsonand/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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →