/** @type {import('next').NextConfig} */ const nextConfig = { // Enable standalone output for Docker output: 'standalone', // The /api/* and /sitemap.xml proxies to the FastAPI backend are route // handlers (app/api/[...path]/route.ts, app/sitemap.xml/route.ts) rather // than rewrites, so the backend host is read from FASTAPI_URL at runtime // instead of being baked into the build. // Image optimization images: { remotePatterns: [ { protocol: 'https', hostname: '*.tile.openstreetmap.org' }, { protocol: 'https', hostname: 'tile.openstreetmap.org' }, { protocol: 'https', hostname: 'cdnjs.cloudflare.com' }, ], formats: ['image/avif', 'image/webp'], minimumCacheTTL: 31536000, }, // Performance optimizations compiler: { // Remove console logs in production removeConsole: process.env.NODE_ENV === 'production', }, // Compression compress: true, // React strict mode for better error detection reactStrictMode: true, // Power optimizations poweredByHeader: false, // Production source maps (disable for smaller bundles) productionBrowserSourceMaps: false, // Experimental features for performance experimental: { // Optimize package imports optimizePackageImports: ['chart.js', 'react-chartjs-2', 'leaflet'], }, // Headers for caching and security async headers() { return [ { source: '/:path*', headers: [ { key: 'X-DNS-Prefetch-Control', value: 'on', }, { // Allow the analytics subdomain (Umami heatmap/recorder) to embed // the site while blocking all other origins. frame-ancestors is the // modern replacement for X-Frame-Options, which cannot allow a // specific sibling subdomain (ALLOW-FROM is deprecated/ignored). key: 'Content-Security-Policy', value: "frame-ancestors 'self' https://analytics.schoolcompare.co.uk", }, { key: 'X-Content-Type-Options', value: 'nosniff', }, { key: 'Referrer-Policy', value: 'origin-when-cross-origin', }, ], }, { source: '/favicon.svg', headers: [ { key: 'Cache-Control', value: 'public, max-age=31536000, immutable', }, ], }, ]; }, }; module.exports = nextConfig;