import type { NextConfig } from "next"; import dotenv from "dotenv"; import path from "path"; import bundleAnalyzer from "@next/bundle-analyzer"; // Load the .env file from the working directory dotenv.config({ path: path.resolve(process.cwd(), ".env") }); const nextConfig: NextConfig = { // Enable standalone output for Docker output: "standalone", outputFileTracingRoot: path.join(process.cwd()), // Optimize for production compress: true, poweredByHeader: false, // React Strict Mode reactStrictMode: true, // Disable ESLint during build for Docker eslint: { ignoreDuringBuilds: process.env.NODE_ENV === "production", }, // Environment variables env: { NEXT_PUBLIC_BASE_URL: process.env.NEXT_PUBLIC_BASE_URL, }, // Performance optimizations experimental: { optimizePackageImports: ["lucide-react", "framer-motion"], }, // Image optimization images: { formats: ["image/webp", "image/avif"], minimumCacheTTL: 60, remotePatterns: [ { protocol: "https", hostname: "i.scdn.co", }, { protocol: "https", hostname: "cdn.discordapp.com", }, { protocol: "https", hostname: "media.discordapp.net", }, ], }, // Webpack configuration webpack: (config, { isServer, dev, webpack }) => { // Fix for module resolution issues config.resolve.fallback = { ...config.resolve.fallback, fs: false, net: false, tls: false, }; // Safari + React 19 + Next.js 15 compatibility fixes if (dev && !isServer) { // Disable module concatenation to prevent factory initialization issues config.optimization = { ...config.optimization, concatenateModules: false, providedExports: false, usedExports: false, }; // Add DefinePlugin to ensure proper environment detection config.plugins.push( new webpack.DefinePlugin({ "process.env.__NEXT_DISABLE_REACT_STRICT_MODE": JSON.stringify(false), }), ); } return config; }, // Security and cache headers async headers() { return [ { source: "/(.*)", headers: [ { key: "X-DNS-Prefetch-Control", value: "on", }, { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload", }, { key: "X-Frame-Options", value: "DENY", }, { key: "X-Content-Type-Options", value: "nosniff", }, { key: "X-XSS-Protection", value: "1; mode=block", }, { key: "Referrer-Policy", value: "strict-origin-when-cross-origin", }, { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()", }, { key: "Content-Security-Policy", value: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://analytics.dk0.dev; script-src-elem 'self' 'unsafe-inline' https://analytics.dk0.dev; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: https:; connect-src 'self' https://analytics.dk0.dev https://api.quotable.io; frame-ancestors 'none'; base-uri 'self'; form-action 'self';", }, ], }, { source: "/api/(.*)", headers: [ { key: "Cache-Control", value: "no-store, no-cache, must-revalidate, proxy-revalidate", }, ], }, { source: "/_next/static/(.*)", headers: [ { key: "Cache-Control", value: "public, max-age=31536000, immutable", }, ], }, ]; }, }; const withBundleAnalyzer = bundleAnalyzer({ enabled: process.env.ANALYZE === "true", }); export default withBundleAnalyzer(nextConfig);