SkateSpots/vite.config.ts
shakespeare.diy 5334144d27 Fix native white screen: relative asset base + boot crash guard
Two changes targeting the post-update white screen on the Zapstore APK:

1. vite.config: set base './' when CAPACITOR_BUILD is set. In a native
   WebView the bundle is served from the local filesystem, so absolute '/'
   asset paths are the classic cause of a silent white screen. The web
   deploy keeps '/'. This is the documented Capacitor requirement and is
   zero-risk to the working web build.

2. index.html: add a dependency-free "boot crash guard" that runs before
   the app bundle and paints any uncaught error / unhandled rejection —
   plus a 12s "did not render" timeout — directly to the screen using
   inline styles only. A boot failure that would otherwise be an
   info-less white screen now shows the actual error ON DEVICE, with no
   USB/remote-debugging needed. main.tsx signals a clean boot to cancel
   the timeout guard.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-24 18:21:57 +07:00

108 lines
3.5 KiB
TypeScript

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: {
// Native Capacitor plugins have no JS entry point — they are injected
// at runtime by Capacitor on the native side. Exclude them from the bundle.
external: [
'nostr-signer-capacitor-plugin',
'@capacitor/camera',
'@capacitor/core',
'@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'],
},
}));