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, }, // 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}'], }, });