import { defineConfig, UserConfig, Plugin } from "vite"; import vue from "@vitejs/plugin-vue"; import dotenv from "dotenv"; import { loadAppConfig } from "./vite.config.utils.mts"; import path from "path"; import { fileURLToPath } from 'url'; // Load environment variables dotenv.config(); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); export async function createBuildConfig(mode: string): Promise { const appConfig = await loadAppConfig(); const isCapacitor = mode === "capacitor"; const isElectron = mode === "electron"; const isNative = isCapacitor || isElectron; // Set platform and disable PWA for native platforms process.env.VITE_PLATFORM = mode; process.env.VITE_PWA_ENABLED = isNative ? 'false' : 'true'; process.env.VITE_DISABLE_PWA = isNative ? 'true' : 'false'; if (isNative) { process.env.VITE_PWA_ENABLED = 'false'; } return { base: "/", plugins: [vue()], server: { port: parseInt(process.env.VITE_PORT || "8080"), fs: { strict: false }, headers: { // Enable SharedArrayBuffer for absurd-sql 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }, proxy: { // Proxy API requests to avoid CORS issues with restrictive headers '/api': { target: 'http://localhost:3000', changeOrigin: true, secure: false, configure: (proxy) => { proxy.on('error', (err, req, res) => { console.log('[Proxy Error]', err); }); proxy.on('proxyReq', (proxyReq, req, res) => { console.log('[Proxy Request]', req.method, req.url, '->', proxyReq.path); }); } }, // Proxy partner API requests (redirect to main API) '/partner-api': { target: 'http://localhost:3000', changeOrigin: true, secure: false, rewrite: (path) => path.replace(/^\/partner-api/, '/api'), configure: (proxy) => { proxy.on('error', (err, req, res) => { console.log('[Partner API Proxy Error]', err); }); proxy.on('proxyReq', (proxyReq, req, res) => { console.log('[Partner API Proxy Request]', req.method, req.url, '->', proxyReq.path); }); } }, // Proxy image API requests '/image-api': { target: 'https://test-image-api.timesafari.app', changeOrigin: true, secure: true, rewrite: (path) => path.replace(/^\/image-api/, ''), configure: (proxy) => { proxy.on('error', (err, req, res) => { console.log('[Image API Proxy Error]', err); }); proxy.on('proxyReq', (proxyReq, req, res) => { console.log('[Image API Proxy Request]', req.method, req.url, '->', proxyReq.path); }); } }, // Proxy direct image requests from image.timesafari.app to avoid CORS issues '/image-proxy': { target: 'https://image.timesafari.app', changeOrigin: true, secure: true, followRedirects: true, rewrite: (path) => path.replace(/^\/image-proxy/, ''), configure: (proxy) => { proxy.on('error', (err, req, res) => { console.log('[Image Proxy Error]', err); }); proxy.on('proxyReq', (proxyReq, req, res) => { console.log('[Image Proxy Request]', req.method, req.url, '->', proxyReq.path); }); proxy.on('proxyRes', (proxyRes, req, res) => { // Log the response to debug redirects console.log('[Image Proxy Response]', req.url, '->', proxyRes.statusCode, proxyRes.headers.location || 'no redirect'); }); } }, // Proxy Flickr images to avoid CORS issues '/flickr-proxy': { target: 'https://live.staticflickr.com', changeOrigin: true, secure: true, followRedirects: true, rewrite: (path) => path.replace(/^\/flickr-proxy/, ''), configure: (proxy) => { proxy.on('error', (err, req, res) => { console.log('[Flickr Proxy Error]', err); }); proxy.on('proxyReq', (proxyReq, req, res) => { console.log('[Flickr Proxy Request]', req.method, req.url, '->', proxyReq.path); }); proxy.on('proxyRes', (proxyRes, req, res) => { // Add CORS headers to the response proxyRes.headers['Access-Control-Allow-Origin'] = '*'; proxyRes.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS'; proxyRes.headers['Access-Control-Allow-Headers'] = 'Content-Type'; console.log('[Flickr Proxy Response]', req.url, '->', proxyRes.statusCode); }); } } } }, build: { outDir: "dist", assetsDir: 'assets', chunkSizeWarningLimit: 1000, rollupOptions: { external: isNative ? ['@capacitor/app'] : [], output: { format: 'esm', generatedCode: { preset: 'es2015' }, manualChunks: undefined } } }, worker: { format: 'es', plugins: () => [] }, define: { 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), 'process.env.VITE_PLATFORM': JSON.stringify(mode), 'process.env.VITE_PWA_ENABLED': JSON.stringify(!isNative), 'process.env.VITE_DISABLE_PWA': JSON.stringify(isNative), __dirname: JSON.stringify(process.cwd()), __IS_MOBILE__: JSON.stringify(isCapacitor), __IS_ELECTRON__: JSON.stringify(isElectron), __USE_QR_READER__: JSON.stringify(!isCapacitor), 'process.platform': JSON.stringify('browser'), 'process.version': JSON.stringify('v16.0.0'), 'process.env.NODE_DEBUG': JSON.stringify(false), 'global.process': JSON.stringify({ platform: 'browser', version: 'v16.0.0', env: { NODE_DEBUG: false } }) }, resolve: { alias: { '@': path.resolve(__dirname, 'src'), '@nostr/tools': path.resolve(__dirname, 'node_modules/@nostr/tools'), '@nostr/tools/nip06': path.resolve(__dirname, 'node_modules/@nostr/tools/nip06'), ...appConfig.aliasConfig, 'path': path.resolve(__dirname, './src/utils/node-modules/path.js'), 'fs': path.resolve(__dirname, './src/utils/node-modules/fs.js'), 'crypto': path.resolve(__dirname, './src/utils/node-modules/crypto.js'), 'dexie-export-import': path.resolve(__dirname, 'node_modules/dexie-export-import') } }, optimizeDeps: { include: [ '@nostr/tools', '@nostr/tools/nip06', ], exclude: isNative ? [ 'register-service-worker', 'workbox-window', 'web-push', 'serviceworker-webpack-plugin', 'vite-plugin-pwa', '@vite-pwa/vue' ] : [] } }; } export default defineConfig(async () => createBuildConfig('web'));