import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { VitePWA } from 'vite-plugin-pwa'; import path from 'path'; import { fileURLToPath } from 'url'; import { createRequire } from 'module'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const require = createRequire(import.meta.url); const pkg = require('./package.json'); const apiPort = process.env.API_PORT || process.env.PORT || 3000; export default defineConfig({ plugins: [ react(), VitePWA({ registerType: 'autoUpdate', includeAssets: ['img/logo.png', 'img/pwa-192.png', 'img/pwa-512.png'], manifest: { name: 'BillTracker', short_name: 'BillTracker', description: 'Personal bill planning and tracking', theme_color: '#18181b', background_color: '#18181b', display: 'standalone', start_url: '/', icons: [ { src: '/img/pwa-192.png', sizes: '192x192', type: 'image/png' }, { src: '/img/pwa-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' }, ], }, workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'], runtimeCaching: [ { urlPattern: /^\/api\/(tracker|bills|calendar|summary|analytics|snowball|categories)/, handler: 'NetworkFirst', options: { cacheName: 'api-cache', networkTimeoutSeconds: 5, expiration: { maxEntries: 30, maxAgeSeconds: 300 }, }, }, ], }, }), ], publicDir: 'client/public', define: { // Injected at build time — frontend reads this instead of maintaining a // duplicate version string in client/lib/version.js __APP_VERSION__: JSON.stringify(pkg.version), }, resolve: { alias: { '@': path.resolve(__dirname, './client') }, }, server: { port: 5173, proxy: { '/api': { target: `http://localhost:${apiPort}`, changeOrigin: true }, }, }, build: { outDir: 'dist', emptyOutDir: true, rollupOptions: { output: { // QA-B0-01: split the shared vendor code out of the ~659 kB index chunk // so large libs load/cache independently and the main bundle shrinks. manualChunks: { 'vendor-react': ['react', 'react-dom', 'react-router-dom'], 'vendor-radix': [ '@radix-ui/react-dialog', '@radix-ui/react-select', '@radix-ui/react-dropdown-menu', '@radix-ui/react-tabs', '@radix-ui/react-tooltip', '@radix-ui/react-alert-dialog', ], 'vendor-motion': ['framer-motion'], 'vendor-query': ['@tanstack/react-query', '@tanstack/react-virtual'], }, }, }, }, // Vitest — client-side unit tests (pure logic in client/lib). // Server tests stay on node:test (`npm run test`); client tests run with // `npm run test:client`; `npm run test:all` runs both. test: { environment: 'node', // hook/component tests opt into jsdom via @vitest-environment include: ['client/**/*.test.{js,jsx}'], }, });