vkashti / next.config.js.original
next.config.js.original
Raw
/** @type {import('next').NextConfig} */
const path = require('path');

const nextConfig = {
  // Transpile framer-motion
  transpilePackages: ['framer-motion', 'motion-dom', 'motion-utils'],
  // Enable source maps in production for better debugging
  productionBrowserSourceMaps: true,
  // Additional security headers
  headers: async () => {
    return [
      {
        source: '/(.*)',
        headers: [
          {
            key: 'X-Content-Type-Options',
            value: 'nosniff',
          },
          {
            key: 'X-XSS-Protection',
            value: '1; mode=block',
          },
          // Add HSTS header with preload
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=31536000; includeSubDomains; preload',
          },
          // Add header to help with bfcache
          {
            key: 'Cache-Control',
            value: 'public, max-age=3600, s-maxage=86400, stale-while-revalidate=31536000',
          },
          // Enable back/forward cache
          {
            key: 'Service-Worker-Allowed',
            value: '/',
          },
        ],
      },
      // Improved cache control for static assets with longer TTL
      {
        source: '/(.*)\\.(jpg|jpeg|gif|png|svg|webp|avif|woff|woff2)$',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable',
          },
          // Add content type for WebP images to ensure proper handling
          {
            key: 'Vary',
            value: 'Accept',
          },
        ],
      },
      // Add cache control for JS and CSS with appropriate max-age
      {
        source: '/(.*)\\.(js|css|map)$',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable',
          },
          // Add content encoding header for compression
          {
            key: 'Content-Encoding',
            value: 'br, gzip',
          },
          // Ensure proper MIME type for source maps
          {
            key: 'Content-Type',
            value: 'application/json',
          },
        ],
      },
      // Add cache control for HTML and data requests
      {
        source: '/$',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=3600, stale-while-revalidate=86400',
          },
        ],
      },
    ];
  },
  // Ensure output is static where possible
  output: 'standalone',
  
  // Add optimizeFonts for better font performance
  optimizeFonts: true,
  
  // Improved image optimization settings
  images: {
    formats: ['image/webp', 'image/avif'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    minimumCacheTTL: 60 * 60 * 24 * 30, // 30 days
    dangerouslyAllowSVG: true,
    contentDispositionType: 'attachment',
    contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
    // Limit image sizes to reduce payload
    remotePatterns: [],
    domains: [],
  },
  
  // Enable compression middleware - ensure this is enabled
  compress: true,
  
  // Performance optimizations with stable experimental features
  experimental: {
    // Enable React Server Components optimizations
    serverActions: {
      bodySizeLimit: '2mb',
    },
    // External packages that should be compiled
    serverComponentsExternalPackages: ['@supabase/supabase-js'],
    // Enable optimizeCss to remove unused CSS
    optimizeCss: true,
    // Improved memory usage
    memoryBasedWorkersCount: true,
    // Reduce unused JavaScript via partial imports
    optimizePackageImports: ['react-icons', 'framer-motion', 'lucide-react'],
  },
  
  // Webpack configuration for performance optimization
  webpack: (config, { dev, isServer }) => {
    // Path aliases already in tsconfig.json should be respected by Next.js
    // but let's add them here explicitly as well
    config.resolve.alias = {
      ...config.resolve.alias,
      '@': path.resolve(__dirname),
    };
    
    // Only run in production build on client
    if (!dev && !isServer) {
      // Split chunks more aggressively for better caching
      config.optimization.splitChunks = {
        chunks: 'all',
        maxInitialRequests: 25,
        minSize: 20000,
        maxSize: 244000, // Limit chunk size to reduce main thread parse time
        cacheGroups: {
          default: false,
          vendors: false,
          framework: {
            name: 'framework',
            test: /[\\/]node_modules[\\/](react|react-dom|scheduler|next)[\\/]/,
            priority: 40,
            enforce: true,
          },
          // Create a separate chunk for large libraries
          framerMotion: {
            test: /[\\/]node_modules[\\/](framer-motion)[\\/]/,
            name: 'framer-motion',
            priority: 35,
            reuseExistingChunk: true,
          },
          // Group all react icons separately
          reactIcons: {
            test: /[\\/]node_modules[\\/](react-icons)[\\/]/,
            name: 'react-icons',
            priority: 35,
            reuseExistingChunk: true,
          },
          lib: {
            test: /[\\/]node_modules[\\/]/,
            name(module) {
              const match = module.context ? module.context.match(
                /[\\/]node_modules[\\/](.*?)([\\/]|$)/
              ) : null;
              const packageName = match ? match[1] : 'unknown';
              return `npm.${packageName.replace('@', '')}`;
            },
            priority: 30,
            minChunks: 1,
            reuseExistingChunk: true,
          },
          commons: {
            name: 'commons',
            minChunks: 2,
            priority: 20,
          },
        },
      };
      
      // Enable terser minification with better options
      if (config.optimization.minimizer) {
        config.optimization.minimizer.forEach(minimizer => {
          if (minimizer.constructor.name === 'TerserPlugin') {
            minimizer.options.terserOptions = {
              ...minimizer.options.terserOptions,
              compress: {
                ...minimizer.options.terserOptions.compress,
                drop_console: true, // Remove console logs
                pure_funcs: ['console.log', 'console.info', 'console.debug'],
                passes: 3, // More aggressive optimization
                ecma: 2020, // Use modern optimizations
                toplevel: true, // Optimize top-level functions
                unsafe_math: true, // Enable faster math optimizations
                unsafe_methods: true, // Enable unsafe method optimizations
                keep_infinity: true, // Preserve Infinity literals
                module: true, // Enable module compression options
                reduce_funcs: true, // Inline single-use functions when possible
              },
              mangle: {
                ...minimizer.options.terserOptions.mangle,
                safari10: true,
                toplevel: true, // Mangle top-level functions
                module: true, // Enable module mangling
              },
              format: {
                comments: false, // Remove all comments
                ecma: 2020, // Use modern formatting
              },
              module: true, // Enable module processing
              toplevel: true, // Enable top-level optimizations
              keep_classnames: false, // Allow class name mangling
              keep_fnames: false, // Allow function name mangling
            };
          }
          
          // Add CSSO Plugin for CSS minification if available
          if (minimizer.constructor.name === 'CssMinimizerPlugin') {
            minimizer.options.minimizerOptions = {
              preset: ['advanced', { 
                discardComments: { removeAll: true },
                mergeIdents: true,
                reduceIdents: true,
                zindex: false,
              }],
            };
          }
        });
      }
      
      // Disable source maps in production
      config.devtool = false;
      
      // Add image optimization - ensure it's available
      try {
        // Use responsive-loader if available
        const { resolve } = require('path');
        const responsiveLoader = resolve(process.cwd(), 'node_modules/responsive-loader');
        
        if (require('fs').existsSync(responsiveLoader)) {
          config.module.rules.push({
            test: /\.(jpe?g|png|gif)$/i,
            use: [
              {
                loader: 'responsive-loader',
                options: {
                  adapter: require('responsive-loader/sharp'),
                  quality: 80,
                  placeholder: true,
                  placeholderSize: 40,
                  format: 'webp',
                  progressive: true,
                },
              },
            ],
          });
          console.log('✅ Responsive image loader enabled');
        }
      } catch (e) {
        console.warn('⚠️ Could not enable responsive-loader', e.message);
      }
    }
    
    return config;
  },
  
  // Reduce power usage on browsers
  poweredByHeader: false,
  
  // Configure Next.js to automatically set gzip/brotli compression
  async rewrites() {
    return [];
  },
  
  // Configure React optimization options
  reactStrictMode: true,
};

module.exports = nextConfig;