import { defineConfig, loadEnv } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' import path from 'path' import fs from 'fs' /** Same default as server when `server/.env` has no PORT (see repo root `mailflow.dev.port.json`). */ function readMailflowDevPort(): string { const f = path.resolve(__dirname, '../mailflow.dev.port.json') try { const j = JSON.parse(fs.readFileSync(f, 'utf8')) as { port?: number } if (j.port != null && Number.isFinite(Number(j.port))) return String(j.port) } catch { /* missing or invalid */ } return '3030' } /** Align Vite proxy with server/.env PORT (client/.env does not load server PORT). */ function readBackendPortFromServerEnv(): string { const envFile = path.resolve(__dirname, '../server/.env') try { let text = fs.readFileSync(envFile, 'utf8') if (text.charCodeAt(0) === 0xfeff) text = text.slice(1) for (const line of text.split(/\r?\n/)) { if (/^\s*#/.test(line)) continue const noComment = line.split('#')[0]?.trim() || '' const m = /^\s*PORT\s*=\s*"?(\d+)"?/i.exec(noComment) if (m) return m[1] } } catch { /* no server/.env */ } return readMailflowDevPort() } /** Origin only (no trailing /api) — matches client api.ts / VITE_DEV_BACKEND_ORIGIN contract. */ function stripTrailingApiFromOrigin(o: string): string { let s = o.replace(/\/$/, '') while (s.endsWith('/api')) { s = s.slice(0, -4).replace(/\/+$/, '') } return s } // https://vite.dev/config/ export default defineConfig(({ mode }) => { const env = loadEnv(mode, __dirname, '') const appwriteDevOrigin = (env.APPWRITE_DEV_ORIGIN || '').replace(/\/$/, '') const defaultApiOrigin = `http://127.0.0.1:${readBackendPortFromServerEnv()}` // 127.0.0.1 avoids Windows localhost → IPv6 (::1) vs backend listening on IPv4-only const apiDevTarget = stripTrailingApiFromOrigin(env.VITE_DEV_API_ORIGIN || defaultApiOrigin) const proxy: Record< string, { target: string; changeOrigin: boolean; secure?: boolean } > = { '/api': { target: apiDevTarget, changeOrigin: true, }, '/stripe': { target: apiDevTarget, changeOrigin: true, }, } // Dev: Browser → localhost:5173/v1/* → Appwrite (umgeht CORS, wenn die Console nur z. B. webklar.com erlaubt) if (mode === 'development' && appwriteDevOrigin) { proxy['/v1'] = { target: appwriteDevOrigin, changeOrigin: true, secure: true, } } return { // Browser ruft Express direkt an (CORS) — vermeidet 404, wenn der Vite-/api-Proxy nicht greift define: mode === 'development' ? { 'import.meta.env.VITE_DEV_BACKEND_ORIGIN': JSON.stringify(apiDevTarget), } : {}, plugins: [react(), tailwindcss()], resolve: { alias: { '@': path.resolve(__dirname, './src'), }, }, server: { host: true, port: 5173, // Wenn 5173 schon belegt ist, nicht still auf einen anderen Port wechseln — sonst öffnet man oft noch die alte URL und bekommt für /api 404. strictPort: true, proxy, }, // `vite preview` hat standardmäßig keinen Dev-Proxy — sonst wäre /api ein 404. preview: { proxy }, } })