/* eslint-env node */ import bundleAnalyzer from "@next/bundle-analyzer"; const withBundleAnalyzer = bundleAnalyzer({ enabled: process.env.ANALYZE === "true", }); import path from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); /** @type {import('next').NextConfig} */ const nextConfig = { // Enable standalone output only for production deployment output: process.env.NODE_ENV === "production" ? "standalone" : undefined, // Ensure workspace packages are transpiled correctly transpilePackages: ["@customer-portal/domain", "@customer-portal/validation"], // Tell Next to NOT bundle these server-only libs serverExternalPackages: [ "pino", "pino-pretty", "pino-abstract-transport", "thread-stream", "sonic-boom", // Avoid flaky vendor-chunk resolution during dev for small utils "tailwind-merge", ], // Turbopack configuration (Next.js 15.5+) // Note: public turbopack options are limited; aliasing is handled via tsconfig/webpack resolutions // Environment variables validation env: { NEXT_PUBLIC_API_BASE: process.env.NEXT_PUBLIC_API_BASE, NEXT_PUBLIC_APP_NAME: process.env.NEXT_PUBLIC_APP_NAME, NEXT_PUBLIC_APP_VERSION: process.env.NEXT_PUBLIC_APP_VERSION, }, // Image optimization images: { remotePatterns: [ { protocol: "https", hostname: "**", }, ], }, // Disable ESLint blocking during production builds to avoid CI/CD failures eslint: { ignoreDuringBuilds: true, }, // Security headers async headers() { return [ { // Apply security headers to all routes source: "/(.*)", headers: [ { key: "X-Frame-Options", value: "DENY", }, { key: "X-Content-Type-Options", value: "nosniff", }, { key: "Referrer-Policy", value: "strict-origin-when-cross-origin", }, { key: "X-XSS-Protection", value: "1; mode=block", }, // Content Security Policy - development-friendly { key: "Content-Security-Policy", value: process.env.NODE_ENV === "development" ? "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https: http://localhost:* ws://localhost:*; frame-ancestors 'none';" : [ "default-src 'self'", "script-src 'self'", "style-src 'self'", "img-src 'self' data: https:", "font-src 'self' data:", "connect-src 'self'", "frame-ancestors 'none'", ].join("; "), }, ], }, ]; }, // Production optimizations compiler: { // Remove console.logs in production removeConsole: process.env.NODE_ENV === "production", }, // Experimental flags experimental: { externalDir: true, optimizePackageImports: ["@heroicons/react", "lucide-react", "@tanstack/react-query"], }, webpack(config) { const workspaceRoot = path.resolve(__dirname, "..", ".."); config.resolve.alias = { ...config.resolve.alias, "@customer-portal/domain": path.join(workspaceRoot, "packages/domain"), "@customer-portal/validation": path.join(workspaceRoot, "packages/validation/src"), }; const preferredExtensions = [".ts", ".tsx", ".mts", ".cts"]; const existingExtensions = config.resolve.extensions || []; config.resolve.extensions = [...new Set([...preferredExtensions, ...existingExtensions])]; config.resolve.extensionAlias = { ...(config.resolve.extensionAlias || {}), ".js": [".ts", ".tsx", ".js"], ".mjs": [".mts", ".ts", ".tsx", ".mjs"], }; config.module.rules.push({ test: /packages\/domain\/.*\.js$/, type: "javascript/esm", }); return config; }, // Keep type checking enabled; monorepo paths provide types typescript: { ignoreBuildErrors: false }, // Prefer Turbopack; no custom webpack override needed }; export default withBundleAnalyzer(nextConfig);