import { wayfinder } from '@laravel/vite-plugin-wayfinder'; import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; import laravel from 'laravel-vite-plugin'; import { defineConfig, type PluginOption } from 'vite'; import path from 'path'; import { tamaguiPlugin } from '@tamagui/vite-plugin'; import { sentryVitePlugin } from '@sentry/vite-plugin'; import { VitePWA } from 'vite-plugin-pwa'; const devServerHost = process.env.VITE_DEV_SERVER_HOST ?? 'fotospiel-app.test'; const devServerPort = Number.parseInt(process.env.VITE_DEV_SERVER_PORT ?? '5173', 10); const devServerOrigin = process.env.VITE_DEV_SERVER_URL ?? `http://fotospiel-app.test:${devServerPort}`; const parsedOrigin = new URL(devServerOrigin); const hmrPort = parsedOrigin.port === '' ? devServerPort : Number.parseInt(parsedOrigin.port, 10); const appUrl = process.env.APP_URL ?? 'http://fotospiel-app.test'; const sentryEnabled = Boolean( process.env.SENTRY_AUTH_TOKEN && process.env.SENTRY_ORG && process.env.SENTRY_PROJECT && process.env.SENTRY_URL ); const plugins: PluginOption[] = [ laravel({ input: ['resources/css/app.css','resources/js/app.js', 'resources/js/app.tsx', 'resources/js/guest/main.tsx', 'resources/js/admin/main.tsx'], ssr: 'resources/js/ssr.tsx', refresh: [ 'resources/views/**/*.blade.php', 'resources/lang/**/*.php', 'app/Http/Livewire/**', // falls genutzt // NICHT beobachten: storage/logs, vendor, public/build, etc. ], }), react(), tailwindcss(), wayfinder({ formVariants: true, }), VitePWA({ strategies: 'injectManifest', srcDir: 'resources/js/guest', filename: 'guest-sw.ts', manifestFilename: 'guest.webmanifest', outDir: 'public', injectRegister: null, registerType: 'prompt', includeAssets: [ 'favicon.ico', 'favicon.svg', 'apple-touch-icon.png', 'logo-transparent-md.png', 'logo-transparent-lg.png', ], injectManifest: { globDirectory: 'public/build', globPatterns: ['**/*.{js,css,woff,woff2,svg,png,webp,ico,txt}'], }, manifest: { name: 'Fotospiel', short_name: 'Fotospiel', id: '/event', start_url: '/event', scope: '/', display: 'standalone', lang: 'de-DE', description: 'Offline-fähige Event-Galerie für Gäste – Fotos aufnehmen, Aufgaben lösen und teilen.', background_color: '#0f172a', theme_color: '#ec4899', orientation: 'portrait', categories: ['photo-video', 'social'], icons: [ { src: '/favicon.svg', sizes: 'any', type: 'image/svg+xml', purpose: 'any', }, { src: '/apple-touch-icon.png', sizes: '166x169', type: 'image/png', purpose: 'any', }, { src: '/logo-transparent-lg.png', sizes: '698x684', type: 'image/png', purpose: 'any', }, ], }, devOptions: { enabled: false, }, }), tamaguiPlugin({ config: './tamagui.config.ts', components: ['@tamagui/core', '@tamagui/stacks', '@tamagui/text', '@tamagui/button'], optimize: false, disableExtraction: true, }), ]; if (sentryEnabled) { plugins.push( sentryVitePlugin({ org: process.env.SENTRY_ORG as string, project: process.env.SENTRY_PROJECT as string, authToken: process.env.SENTRY_AUTH_TOKEN as string, url: process.env.SENTRY_URL as string, release: process.env.SENTRY_RELEASE ?? process.env.VITE_SENTRY_RELEASE, telemetry: false, }) ); } export default defineConfig({ server: { host: devServerHost, port: devServerPort, strictPort: true, origin: devServerOrigin, hmr: { host: parsedOrigin.hostname, protocol: parsedOrigin.protocol.replace(':','') as 'http' | 'https', clientPort: hmrPort, }, fs: { strict: true, // Erlaube nur das App-Package (ggf. Pfade anpassen) allow: [__dirname], }, cors: { origin: appUrl, credentials: true, }, watch: { // WENIGER ist mehr: Alles ausklammern, was nicht für HMR nötig ist ignored: [ '**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**', '**/.next/**', '**/coverage/**', '**/.cache/**', // Laravel-spezifisch '**/public/build/**', '**/storage/**', '**/vendor/**', '**/bootstrap/cache/**', // Monorepo-Nachbarn '../**/node_modules/**', '../**/dist/**', '../**/build/**', '../**/coverage/**', ], // Falls ihr auf gemounteten FS seid und Events fehlen: // usePolling: true, interval: 500, }, proxy: { '/fonts': { target: appUrl, changeOrigin: true, }, }, }, plugins, esbuild: { jsx: 'automatic', }, optimizeDeps: { // Bei großen Monorepos hilfreich: entries: ['resources/js/**/*'], exclude: [ // füge notfalls große/selten genutzte Pakete hinzu ], include: [ 'react-native-web', '@tamagui/core', '@tamagui/stacks', '@tamagui/text', '@tamagui/button', ], }, define: { 'process.env.TAMAGUI_TARGET': JSON.stringify('web'), }, // Build-Optionen wirken vor allem bei `vite build`, schaden aber nicht: build: { sourcemap: sentryEnabled, target: 'es2020', rollupOptions: { // keine externen Monster-Globs }, }, });