/// import { defineConfig, loadEnv, type Plugin } from 'vite' import react from '@vitejs/plugin-react' import path from 'path' import { visualizer } from 'rollup-plugin-visualizer' // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { const isProduction = mode === 'production' const projectRoot = path.resolve(__dirname) // Load VITE_DOMAIN from .env files (single source of truth for the domain) const envVars = loadEnv(mode, projectRoot, 'VITE_') const domain = envVars.VITE_DOMAIN || 'veza.fr' const backendPort = envVars.VITE_BACKEND_PORT || '18080' const chatPort = envVars.VITE_CHAT_PORT || '18081' const streamPort = envVars.VITE_STREAM_PORT || '18082' return { // Ensure dev server and dep scan use apps/web only (avoid picking up storybook-static when run from monorepo root) root: projectRoot, plugins: [ react(), // Bundle analyzer for production builds (isProduction && visualizer({ filename: 'dist/bundle-analysis.html', open: false, gzipSize: true, brotliSize: true, })) as Plugin, ].filter(Boolean), test: { globals: true, environment: 'jsdom', setupFiles: './src/setupTests.ts', css: true, }, resolve: { alias: { '@': path.resolve(__dirname, './src'), '@components': path.resolve(__dirname, './src/components'), '@features': path.resolve(__dirname, './src/features'), '@services': path.resolve(__dirname, './src/services'), '@hooks': path.resolve(__dirname, './src/hooks'), '@utils': path.resolve(__dirname, './src/utils'), '@types': path.resolve(__dirname, './src/types'), }, }, server: { port: parseInt(process.env.PORT || '5173', 10), host: true, // Allow dev access via the configured domain (VITE_DOMAIN in .env.local) allowedHosts: [domain], // Exclude Storybook build output from watch and fs access so dep scan never touches it watch: { ignored: ['**/storybook-static/**', '**/dist_verification/**'], }, fs: { deny: ['**/storybook-static/**', '**/dist_verification/**'], }, // P2.1: Proxy API and Swagger requests to backend in development // This eliminates CORS issues in dev by making all requests same-origin proxy: { '/api': { target: `http://${domain}:${backendPort}`, changeOrigin: true, secure: false, ws: true, }, '/swagger': { target: `http://${domain}:${backendPort}`, changeOrigin: true, secure: false, }, '/ws': { target: `http://${domain}:${backendPort}`, changeOrigin: true, ws: true, rewrite: (path: string) => path.replace(/^\/ws/, '/api/v1/ws'), }, '/stream': { target: `http://${domain}:${streamPort}`, changeOrigin: true, ws: true, }, '/hls': { target: `http://${domain}:${streamPort}`, changeOrigin: true, secure: false, }, }, }, build: { outDir: 'dist_verification', sourcemap: isProduction ? 'hidden' : true, target: 'esnext', minify: 'esbuild', rollupOptions: { output: { manualChunks: (id) => { // Core Vendors if (id.includes('node_modules/react/') || id.includes('node_modules/react-dom/') || id.includes('node_modules/react/jsx-runtime')) { return 'vendor-react'; } if (id.includes('node_modules')) { if (id.includes('react-router')) return 'vendor-router'; if (id.includes('@tanstack')) return 'vendor-tanstack'; if (id.includes('lucide-react')) return 'vendor-icons'; if (id.includes('date-fns')) return 'vendor-utils'; if (id.includes('zod')) return 'vendor-utils'; if (id.includes('framer-motion')) return 'vendor-motion'; if (id.includes('dompurify')) return 'vendor-security'; if (id.includes('axios')) return 'vendor-http'; if (id.includes('i18next')) return 'vendor-i18n'; // Lazy-loaded heavy deps — split from catch-all if (id.includes('recharts') || id.includes('d3-')) return 'vendor-charts'; if (id.includes('@radix-ui')) return 'vendor-radix'; if (id.includes('zustand') || id.includes('immer')) return 'vendor-state'; if (id.includes('@dnd-kit')) return 'vendor-dnd'; if (id.includes('react-hook-form') || id.includes('@hookform')) return 'vendor-forms'; if (id.includes('emoji-picker-react')) return 'vendor-emoji'; if (id.includes('hls.js')) return 'vendor-media'; if (id.includes('@sentry')) return 'vendor-sentry'; if (id.includes('swagger-ui')) return 'vendor-swagger'; if (id.includes('@juspay-tech') || id.includes('hyper')) return 'vendor-payments'; if (id.includes('react-hot-toast')) return 'vendor-toast'; if (id.includes('react-dropzone')) return 'vendor-dropzone'; if (id.includes('class-variance-authority') || id.includes('clsx') || id.includes('tailwind-merge')) return 'vendor-styling'; return 'vendor'; // Remaining small deps } }, }, }, chunkSizeWarningLimit: 1000, }, // Standard optimization settings usually work best optimizeDeps: { include: ['react', 'react-dom'], // Only scan from app entry; avoid storybook-static (and other build outputs) being picked up as entries entries: ['index.html', 'src/main.tsx'], }, } })