import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { VitePWA } from 'vite-plugin-pwa' // https://vite.dev/config/ export default defineConfig({ build: { rollupOptions: { output: { manualChunks: { // Core React dependencies 'vendor-react': ['react', 'react-dom', 'react-router-dom'], // UI/utility libraries (if any large ones are added) // Split pages into separate chunks for lazy loading } } }, // Target modern browsers for smaller bundle target: 'es2020', // Increase chunk size warning limit chunkSizeWarningLimit: 600 }, plugins: [ react(), VitePWA({ registerType: 'autoUpdate', // Force service worker to update immediately devOptions: { enabled: false }, includeAssets: ['favicon.ico', 'robots.txt'], manifest: { name: 'GamerComp', short_name: 'GamerComp', description: 'Where kids become Game Composers! Learn AI communication by creating your own games.', theme_color: '#6366f1', background_color: '#1e1b4b', display: 'standalone', orientation: 'any', scope: '/', start_url: '/', icons: [ { src: '/icon.svg', sizes: 'any', type: 'image/svg+xml', purpose: 'any' }, { src: '/icon.svg', sizes: '512x512', type: 'image/svg+xml', purpose: 'maskable' } ], categories: ['games', 'entertainment', 'education'], screenshots: [ { src: '/screenshot-wide.png', sizes: '1280x720', type: 'image/png', form_factor: 'wide' }, { src: '/screenshot-narrow.png', sizes: '640x1136', type: 'image/png', form_factor: 'narrow' } ] }, workbox: { // Force update without waiting skipWaiting: true, clientsClaim: true, // Import push notification handler importScripts: ['/push-handler.js'], // Use network-first for navigation to always get fresh HTML navigateFallback: 'index.html', navigateFallbackDenylist: [/^\/api/], // Cache strategies runtimeCaching: [ { // Cache API responses (except play/start which needs to be fresh) urlPattern: /^https:\/\/gamercomp\.com\/api\/(?!play\/start|auth).*/i, handler: 'NetworkFirst', options: { cacheName: 'api-cache', expiration: { maxEntries: 100, maxAgeSeconds: 60 * 60 // 1 hour }, cacheableResponse: { statuses: [0, 200] } } }, { // Cache game code for offline play urlPattern: /^https:\/\/gamercomp\.com\/api\/arcade\/games\/\d+$/i, handler: 'CacheFirst', options: { cacheName: 'game-cache', expiration: { maxEntries: 50, maxAgeSeconds: 60 * 60 * 24 * 7 // 1 week }, cacheableResponse: { statuses: [0, 200] } } }, { // Cache fonts urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'google-fonts-cache', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 // 1 year }, cacheableResponse: { statuses: [0, 200] } } }, { // Cache images urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp)$/i, handler: 'CacheFirst', options: { cacheName: 'image-cache', expiration: { maxEntries: 50, maxAgeSeconds: 60 * 60 * 24 * 30 // 30 days } } } ], // Pre-cache essential files globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'] } }) ], })