Files
spotlightcam/frontend/vite.config.js
Radosław Gierwiało f0a1bfb31a feat(pwa): add Progressive Web App support with iOS compatibility
- Install vite-plugin-pwa and workbox-window for PWA functionality
- Configure Vite with full PWA manifest (name, icons, theme, display)
- Add service worker caching for static assets only (no API cache)
- Create app icons (192x192, 512x512, apple-touch-icon)
- Generate iOS splash screens for multiple device sizes
- Add iOS-specific meta tags (apple-mobile-web-app-capable, etc.)
- Implement InstallPWA component with dual platform support:
  - Android/Chrome: beforeinstallprompt event with custom UI
  - iOS Safari: manual installation instructions with icons
- Add dismissal logic with 7-day localStorage persistence
- Update documentation to reflect 90% project completion

PWA implementation focuses on installability and static asset caching
while avoiding offline API cache (WebRTC requires active connection).
2025-11-19 20:59:26 +01:00

99 lines
2.5 KiB
JavaScript

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { VitePWA } from 'vite-plugin-pwa'
// Parse allowed hosts from environment variable
const getAllowedHosts = () => {
const hosts = process.env.VITE_ALLOWED_HOSTS;
// If set to 'all', allow all hosts
if (hosts === 'all') {
return 'all';
}
// If set, parse comma-separated list
if (hosts) {
return hosts.split(',').map(h => h.trim());
}
// Default: localhost only
return ['localhost'];
};
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
includeAssets: ['favicon.ico', 'robots.txt', 'apple-touch-icon.png'],
manifest: {
name: 'spotlight.cam - Dance Event Video Exchange',
short_name: 'spotlight',
description: 'P2P video exchange platform for dance event participants',
theme_color: '#6366f1',
background_color: '#ffffff',
display: 'standalone',
orientation: 'portrait',
scope: '/',
start_url: '/',
icons: [
{
src: '/icons/icon-192x192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any maskable',
},
{
src: '/icons/icon-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable',
},
{
src: '/icons/apple-touch-icon.png',
sizes: '180x180',
type: 'image/png',
},
],
},
workbox: {
// Cache only static assets (no API caching)
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
runtimeCaching: [
{
// Cache images from ui-avatars.com
urlPattern: /^https:\/\/ui-avatars\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'avatar-images',
expiration: {
maxEntries: 100,
maxAgeSeconds: 60 * 60 * 24 * 7, // 7 days
},
cacheableResponse: {
statuses: [0, 200],
},
},
},
],
navigateFallback: null, // Disable offline fallback (app requires internet)
},
devOptions: {
enabled: false, // Disable in dev to avoid conflicts
},
}),
],
server: {
host: '0.0.0.0',
port: 5173,
allowedHosts: getAllowedHosts(),
watch: {
usePolling: true,
},
hmr: {
clientPort: 8080,
},
},
})