import path from "node:path"; import react from "@vitejs/plugin-react-swc"; import { defineConfig } from "vitest/config"; // https://vitejs.dev/config/ export default defineConfig(() => ({ // In a native Capacitor WebView the bundle is served from the local // filesystem, so assets must be referenced with RELATIVE paths ('./…'). // Absolute '/…' paths are the classic cause of a white screen on device. // The regular web deploy keeps '/' (served from a domain root). base: process.env.CAPACITOR_BUILD ? './' : '/', server: { host: "::", port: 8080, }, plugins: [ react(), ], test: { globals: true, environment: 'jsdom', setupFiles: './src/test/setup.ts', onConsoleLog(log) { return !log.includes("React Router Future Flag Warning"); }, env: { DEBUG_PRINT_LIMIT: '0', }, }, resolve: { alias: { "@": path.resolve(__dirname, "./src"), }, }, optimizeDeps: { exclude: ['@lightninglabs/lnc-web'], }, build: { // Strip console.log/warn/debug in production (keeps console.error for real errors) minify: 'esbuild', commonjsOptions: { transformMixedEsModules: true, }, rollupOptions: { // IMPORTANT: installed Capacitor packages (@capacitor/core, @capacitor/camera) // and the signer plugin MUST be bundled. Their JS API layer is real code that // the WebView needs — the *native* implementation is injected at runtime via // window.Capacitor, but the JS imports have to resolve. Externalizing them // leaves bare `import "@capacitor/core"` specifiers in the output, which a // native WebView cannot resolve → "Failed to resolve module specifier" crash. // // Only the Capacitor packages that are NOT installed are kept external, so a // stray import can't break the build. If one of these is ever added to // package.json, remove it from this list so it gets bundled. external: [ '@capacitor/app', '@capacitor/haptics', '@capacitor/keyboard', '@capacitor/status-bar', ], output: process.env.CAPACITOR_BUILD ? { // Single bundle for Capacitor APK — avoids 100+ chunk file requests // that fail silently in Android WebView local file serving manualChunks: undefined, inlineDynamicImports: true, } : { // Split large vendor libraries into separate cacheable chunks. // Users only re-download a chunk when that specific library updates. manualChunks(id) { // Map — Leaflet is large (~150KB), isolate it so non-map pages don't pay for it if (id.includes('leaflet') || id.includes('ngeohash')) { return 'vendor-map'; } // Nostr core — changes infrequently, worth caching separately if (id.includes('nostr-tools') || id.includes('@nostrify') || id.includes('@noble')) { return 'vendor-nostr'; } // Bitcoin / Lightning — large, rarely changes if ( id.includes('@cashu') || id.includes('bitcoinjs-lib') || id.includes('@scure') || id.includes('@bitcoinerlab') || id.includes('ecpair') || id.includes('@getalby') || id.includes('npubcash') ) { return 'vendor-bitcoin'; } // React ecosystem — very stable, long cache life if (id.includes('react-dom') || id.includes('react-router')) { return 'vendor-react'; } // Radix UI components — large but stable if (id.includes('@radix-ui')) { return 'vendor-radix'; } // TanStack Query if (id.includes('@tanstack')) { return 'vendor-query'; } }, }, }, }, // Strip console.log/warn/debug calls from production build esbuild: { drop: ['debugger'], pure: ['console.log', 'console.warn', 'console.debug'], }, }));