import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import svgr from "vite-plugin-svgr"; import { resolve } from "path"; // Custom plugin to bypass Vite 6.1.0 host check bug // The host check middleware runs early, so we intercept and remove it const bypassHostCheck = () => { return { name: 'bypass-host-check', configureServer(server) { // Remove host check middleware by intercepting the middleware stack const originalUse = server.middlewares.use.bind(server.middlewares); server.middlewares.use = function(path, ...handlers) { // Filter out any handler that checks for allowedHosts const filteredHandlers = handlers.filter(handler => { if (typeof handler === 'function') { const handlerStr = handler.toString(); // Skip handlers that check for "allowedHosts" or "not allowed" if (handlerStr.includes('allowedHosts') || handlerStr.includes('not allowed')) { return false; } } return true; }); return originalUse(path, ...filteredHandlers); }; // Also remove from existing stack if (Array.isArray(server.middlewares.stack)) { server.middlewares.stack = server.middlewares.stack.filter(middleware => { if (middleware && middleware.handle) { const handlerStr = middleware.handle.toString(); return !handlerStr.includes('allowedHosts') && !handlerStr.includes('not allowed'); } return true; }); } } }; }; // Plugin to serve marketing.html for SPA routing in marketing dev server const serveMarketingSPA = () => { return { name: 'serve-marketing-spa', configureServer(server) { const isMarketingDev = server.config.server.port === 5174; if (isMarketingDev) { // Handle SPA routing: serve marketing.html for all routes that don't match actual files server.middlewares.use((req, res, next) => { const url = req.url?.split('?')[0] || '/'; // Remove query string // Skip for Vite internal paths and static assets if ( url.startsWith('/@') || // Vite internal (@vite/client, @fs, etc.) url.startsWith('/node_modules') || // Node modules url.startsWith('/src') || // Source files url.startsWith('/api') || // API calls url === '/marketing.html' // Already the marketing HTML ) { return next(); } // Check if URL has a file extension (static asset) const hasFileExtension = /\.\w+$/.test(url); if (hasFileExtension) { return next(); // Let Vite handle static assets } // For all route-like paths (no extension), serve marketing.html // This enables SPA routing for direct URL access (e.g., /product, /pricing) // and browser back/forward navigation req.url = '/marketing.html'; next(); }); } } }; }; // https://vite.dev/config/ export default defineConfig(({ mode, command }) => { // Always enable dev server config when running dev command (serve) const isDev = mode === "development" || command === "serve"; const isMarketingBuild = mode === "marketing"; // Check if we're running marketing dev server (port 5174) const isMarketingDev = process.env.PORT === "5174" || process.argv.includes("--port") && process.argv[process.argv.indexOf("--port") + 1] === "5174"; return { // Set root HTML file for marketing dev server root: __dirname, publicDir: "public", plugins: [ bypassHostCheck(), // Workaround for Vite 6.1.0 host check bug ...(process.env.PORT === "5174" || process.argv.includes("--port") && process.argv[process.argv.indexOf("--port") + 1] === "5174" ? [serveMarketingSPA()] : []), react(), svgr({ svgrOptions: { icon: true, // This will transform your SVG to a React component exportType: "named", namedExport: "ReactComponent", }, }), ], // Optimize dependency pre-bundling optimizeDeps: { include: [ // Core React dependencies - prevent multiple instances "react", "react-dom", "react/jsx-runtime", // Only pre-bundle frequently used, small dependencies "clsx", "tailwind-merge", "zustand", "zustand/middleware", // Required for persist middleware used in stores // Include apexcharts for proper module resolution (skip during marketing-only build) ...(isMarketingBuild ? [] : ["apexcharts", "react-apexcharts"]), // Force include fast-deep-equal for react-dnd compatibility "fast-deep-equal", ], // Exclude heavy dependencies that are only used in specific pages // They will be lazy-loaded when needed exclude: [ "@fullcalendar/core", "@fullcalendar/daygrid", "@fullcalendar/interaction", "@fullcalendar/list", "@fullcalendar/react", "@fullcalendar/timegrid", "@react-jvectormap/core", "@react-jvectormap/world", "swiper", ], esbuildOptions: { target: 'es2020', }, }, // Build configuration for code splitting build: { // Enable minification (esbuild is faster than terser) minify: 'esbuild', // Enable CSS code splitting cssCodeSplit: true, // Optimize chunk size rollupOptions: { input: isMarketingBuild ? { marketing: resolve(__dirname, "marketing.html"), } : { main: resolve(__dirname, "index.html"), marketing: resolve(__dirname, "marketing.html"), }, output: { // Optimize chunk file names chunkFileNames: 'assets/js/[name]-[hash].js', entryFileNames: 'assets/js/[name]-[hash].js', assetFileNames: 'assets/[ext]/[name]-[hash].[ext]', }, }, // Increase chunk size warning limit (default is 500kb) chunkSizeWarningLimit: 600, // Enable source maps in dev only sourcemap: isDev, // Report compressed sizes reportCompressedSize: true, }, // Server configuration - ALWAYS apply (not conditional) // This ensures server config is loaded even with --force flag server: { host: "0.0.0.0", // Allow external connections (for Docker) port: isMarketingBuild ? 5174 : 5173, // Different port for marketing dev strictPort: false, // Allow port fallback if port is busy // Vite 6.1.0: Host check is skipped if allowedHosts === true // Set to true to allow all hosts (safe behind Caddy reverse proxy) // Note: We patched Vite source to always skip host check, but keeping this for safety allowedHosts: true, watch: { usePolling: true, // Needed for file watching in Docker }, hmr: { // Behind reverse proxy - explicitly set host and port to public domain // Client connects via public domain on default HTTPS port (443) // Caddy automatically proxies WebSocket upgrades from 443 to dev port protocol: "wss", host: isMarketingDev ? "igny8.com" : "app.igny8.com", // Marketing uses igny8.com, main app uses app.igny8.com clientPort: 443, // Explicitly set to 443 (HTTPS default) to prevent localhost fallback // This ensures client connects to wss://domain.com:443 // and prevents fallback to localhost:5173/5174 }, // Increase timeout for slow connections and dependency pre-bundling timeout: 120000, // 120 seconds (2 minutes) to match Caddy timeout }, }; });