import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { VitePWA } from 'vite-plugin-pwa' import path from 'path' // https://vite.dev/config/ export default defineConfig({ plugins: [ vue(), VitePWA({ registerType: 'autoUpdate', includeAssets: ['assets/icon/favico-black-v2.svg', 'assets/icon/pwa-64x64-v2.png', 'assets/icon/pwa-192x192-v2.png', 'assets/icon/pwa-512x512-v2.png', 'assets/icon/maskable-icon-512x512-v2.png', 'assets/icon/apple-touch-icon-180x180-v2.png', 'favicon-v2.ico'], manifest: { name: 'Archipelago', short_name: 'Archipelago', description: 'Your sovereign personal server', theme_color: '#000000', background_color: '#000000', display: 'standalone', display_override: ['standalone', 'minimal-ui'], orientation: 'any', scope: '/', start_url: '/', id: '/', categories: ['productivity', 'utilities'], prefer_related_applications: false, icons: [ { src: '/assets/icon/pwa-64x64-v2.png', sizes: '64x64', type: 'image/png', purpose: 'any' }, { src: '/assets/icon/pwa-192x192-v2.png', sizes: '192x192', type: 'image/png', purpose: 'any' }, { src: '/assets/icon/pwa-512x512-v2.png', sizes: '512x512', type: 'image/png', purpose: 'any' }, { src: '/assets/icon/maskable-icon-512x512-v2.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' } ], shortcuts: [ { name: 'Dashboard', short_name: 'Dashboard', description: 'Open the dashboard', url: '/dashboard', icons: [{ src: '/assets/icon/pwa-192x192-v2.png', sizes: '192x192' }] }, { name: 'My Apps', short_name: 'Apps', description: 'Manage your apps', url: '/dashboard/apps', icons: [{ src: '/assets/icon/pwa-192x192-v2.png', sizes: '192x192' }] }, { name: 'App Store', short_name: 'Store', description: 'Browse and install apps', url: '/dashboard/marketplace', icons: [{ src: '/assets/icon/pwa-192x192-v2.png', sizes: '192x192' }] } ] }, workbox: { navigateFallbackDenylist: [/^\/app\//, /^\/rpc\//, /^\/ws/, /^\/aiui\//], globPatterns: ['**/*.{js,css,html,ico,png,svg,jpg,jpeg,mp4,webp}'], globIgnores: [ '**/*-backup-*.mp4', '**/*-1.47mb.mp4', '**/bg-*.mp4', // Exclude large background videos from precache '**/video-intro*.mp4', // Exclude all intro video variants from precache '**/assets/icon/**', // Icons are in includeAssets — don't duplicate in glob precache ], maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // 10MB limit skipWaiting: false, // Wait for user to accept update clientsClaim: false, // Don't claim clients immediately runtimeCaching: [ { urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'google-fonts-cache', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 // 1 year }, cacheableResponse: { statuses: [0, 200] } } }, { urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'gstatic-fonts-cache', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 // 1 year }, cacheableResponse: { statuses: [0, 200] } } }, { urlPattern: /\/rpc\/v1\/.*/i, handler: 'NetworkFirst', options: { cacheName: 'api-cache', expiration: { maxEntries: 50, maxAgeSeconds: 60 * 5 // 5 minutes }, networkTimeoutSeconds: 10 } }, { urlPattern: /\/assets\/.*/i, handler: 'CacheFirst', options: { cacheName: 'assets-cache-v2', expiration: { maxEntries: 100, maxAgeSeconds: 60 * 60 * 24 * 30 // 30 days } } } ] }, devOptions: { enabled: true, type: 'module' } }) ], resolve: { alias: { '@': path.resolve(__dirname, './src') } }, server: { port: 8100, proxy: { '/rpc/v1': { target: process.env.BACKEND_URL || 'http://localhost:5959', changeOrigin: true, secure: false, }, '/ws': { target: process.env.BACKEND_URL || 'http://localhost:5959', ws: true, changeOrigin: true, secure: false, rewrite: (path) => path, // Don't rewrite the path timeout: 0, // No timeout for WebSocket connections }, '/public': { target: process.env.BACKEND_URL || 'http://localhost:5959', changeOrigin: true, secure: false, }, '/rest': { target: process.env.BACKEND_URL || 'http://localhost:5959', changeOrigin: true, secure: false, }, '/app/filebrowser': { target: 'http://192.168.1.228', changeOrigin: true, secure: false, }, }, }, build: { // Output to dist for Docker builds, or to ../web/dist/neode-ui for local development outDir: process.env.DOCKER_BUILD === 'true' ? 'dist' : '../web/dist/neode-ui', emptyOutDir: true, }, })