/** @type {import('next').NextConfig} */ let withBundleAnalyzer = (config) => config; try { withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); } catch (_) { // @next/bundle-analyzer не установлен (например в production Docker-образе) } const nextConfig = { // Оптимизация для production output: 'standalone', // Turbopack конфиг (пустой, используем webpack) turbopack: {}, // Компрессия compress: true, // Оптимизация изображений images: { formats: ['image/avif', 'image/webp'], deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], minimumCacheTTL: 60, dangerouslyAllowSVG: true, contentDispositionType: 'attachment', contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;", }, // Оптимизация webpack webpack: (config, { dev, isServer }) => { // Hot reload для development if (dev) { config.watchOptions = { ...config.watchOptions, poll: 1000, aggregateTimeout: 300, }; } // Оптимизация для production if (!dev && !isServer) { // Агрессивное разделение чанков config.optimization = { ...config.optimization, splitChunks: { chunks: 'all', cacheGroups: { default: false, vendors: false, // Material Web Components в отдельный chunk material: { name: 'material', test: /[\\/]node_modules[\\/]@material[\\/]/, chunks: 'all', priority: 30, enforce: true, }, // LiveKit — скрипты бандлятся с нашего сервера, внешние домены не используются livekit: { name: 'livekit', test: /[\\/]node_modules[\\/](livekit-client|@livekit)[\\/]/, chunks: 'all', priority: 30, enforce: true, }, // React и React DOM react: { name: 'react', test: /[\\/]node_modules[\\/](react|react-dom|scheduler)[\\/]/, chunks: 'all', priority: 25, enforce: true, }, // Axios и другие утилиты utils: { name: 'utils', test: /[\\/]node_modules[\\/](axios|date-fns)[\\/]/, chunks: 'all', priority: 20, }, // Остальные vendor библиотеки vendor: { name: 'vendor', test: /[\\/]node_modules[\\/]/, chunks: 'all', priority: 10, minChunks: 2, }, // Общий chunk для часто используемых модулей common: { name: 'common', minChunks: 2, chunks: 'all', priority: 5, reuseExistingChunk: true, }, }, }, // Минификация minimize: true, }; // Tree shaking для Material Web Components config.resolve.alias = { ...config.resolve.alias, }; } return config; }, // Заголовки для кеширования и безопасности async headers() { return [ { source: '/:path*', headers: [ { key: 'X-DNS-Prefetch-Control', value: 'on', }, { key: 'X-Frame-Options', value: 'SAMEORIGIN', }, { key: 'X-Content-Type-Options', value: 'nosniff', }, { key: 'Referrer-Policy', value: 'origin-when-cross-origin', }, ], }, { source: '/assets/:path*', headers: [ { key: 'Cache-Control', value: 'public, max-age=31536000, immutable', }, ], }, { source: '/_next/static/:path*', headers: [ { key: 'Cache-Control', value: 'public, max-age=31536000, immutable', }, ], }, ]; }, // Rewrites для API async rewrites() { return [ { source: '/api/:path*', destination: `${process.env.NEXT_PUBLIC_API_URL || 'https://api.uchill.online/api'}/:path*`, }, ]; }, // Отключаем x-powered-by для безопасности poweredByHeader: false, // Оптимизация React reactStrictMode: true, // Оптимизация компиляции TypeScript typescript: { ignoreBuildErrors: false, }, }; module.exports = withBundleAnalyzer(nextConfig);