const withPWA = require('next-pwa')({ dest: 'public', register: true, skipWaiting: true, disable: process.env.NODE_ENV === 'development', runtimeCaching: [ { urlPattern: /^https:\/\/fonts\.(?:gstatic)\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'google-fonts-webfonts', expiration: { maxEntries: 4, maxAgeSeconds: 365 * 24 * 60 * 60, // 365 days }, }, }, { urlPattern: /^https:\/\/fonts\.(?:googleapis)\.com\/.*/i, handler: 'StaleWhileRevalidate', options: { cacheName: 'google-fonts-stylesheets', expiration: { maxEntries: 4, maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days }, }, }, { urlPattern: /\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i, handler: 'StaleWhileRevalidate', options: { cacheName: 'static-font-assets', expiration: { maxEntries: 4, maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days }, }, }, { urlPattern: /\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i, handler: 'StaleWhileRevalidate', options: { cacheName: 'static-image-assets', expiration: { maxEntries: 64, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, }, }, { urlPattern: /\/_next\/image\?url=.+$/i, handler: 'StaleWhileRevalidate', options: { cacheName: 'next-image', expiration: { maxEntries: 64, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, }, }, { urlPattern: /\.(?:mp3|wav|ogg)$/i, handler: 'CacheFirst', options: { rangeRequests: true, cacheName: 'static-audio-assets', expiration: { maxEntries: 32, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, }, }, { urlPattern: /\.(?:mp4)$/i, handler: 'CacheFirst', options: { rangeRequests: true, cacheName: 'static-video-assets', expiration: { maxEntries: 32, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, }, }, { urlPattern: /\.(?:js)$/i, handler: 'StaleWhileRevalidate', options: { cacheName: 'static-js-assets', expiration: { maxEntries: 32, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, }, }, { urlPattern: /\.(?:css|less)$/i, handler: 'StaleWhileRevalidate', options: { cacheName: 'static-style-assets', expiration: { maxEntries: 32, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, }, }, { urlPattern: /\/_next\/data\/.+\/.+\.json$/i, handler: 'StaleWhileRevalidate', options: { cacheName: 'next-data', expiration: { maxEntries: 32, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, }, }, { urlPattern: /\/api\/.*$/i, handler: 'NetworkFirst', method: 'GET', options: { cacheName: 'apis', expiration: { maxEntries: 16, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, networkTimeoutSeconds: 10, // fall back to cache if API doesn't respond within 10s }, }, { urlPattern: /.*/i, handler: 'NetworkFirst', options: { cacheName: 'others', expiration: { maxEntries: 32, maxAgeSeconds: 24 * 60 * 60, // 24 hours }, networkTimeoutSeconds: 10, }, }, ], }); /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, // Performance optimizations compiler: { removeConsole: process.env.NODE_ENV === 'production', }, // Image optimization images: { formats: ['image/avif', 'image/webp'], deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], }, // Production optimizations swcMinify: true, // Compression compress: true, // Enable experimental features for better performance experimental: { optimizePackageImports: ['@mui/material', '@mui/icons-material'], }, } module.exports = withPWA(nextConfig)