You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

184 lines
5.6 KiB

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { execSync } from 'child_process';
import { SvelteKitPWA } from '@vite-pwa/sveltekit';
import compression from 'vite-plugin-compression';
import { readFileSync } from 'fs';
import { join } from 'path';
// Read version from package.json for environment variable injection
function getPackageVersion(): string {
try {
const packageJsonPath = join(process.cwd(), 'package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
return packageJson.version || '0.3.2';
} catch {
return '0.3.2';
}
}
export default defineConfig({
publicDir: 'static',
define: {
// Inject version from package.json at build time
'import.meta.env.VITE_APP_VERSION': JSON.stringify(getPackageVersion()),
},
plugins: [
sveltekit(),
compression({
algorithm: 'gzip',
ext: '.gz',
threshold: 1024, // Compress files > 1KB
}),
compression({
algorithm: 'brotliCompress',
ext: '.br',
threshold: 1024,
}),
SvelteKitPWA({
strategies: 'generateSW',
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff,woff2,webp,avif}'],
maximumFileSizeToCacheInBytes: 3 * 1024 * 1024, // 3 MB to handle large chunks
runtimeCaching: [
{
urlPattern: /^https:\/\/.*\.(?:png|jpg|jpeg|svg|gif|webp|avif)$/i,
handler: 'CacheFirst',
options: {
cacheName: 'images-cache',
expiration: {
maxEntries: 200,
maxAgeSeconds: 60 * 60 * 24 * 30 // 30 days
}
}
},
{
// Cache API responses (relay responses) with cache-first strategy for slow connections
urlPattern: /^wss?:\/\//i,
handler: 'CacheFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 200, // Increased from 50
maxAgeSeconds: 60 * 60 * 24 // 24 hours instead of 5 minutes (optimized for slow connections)
}
}
},
{
// Cache static assets with stale-while-revalidate for better performance
urlPattern: /\.(?:js|css|woff|woff2)$/i,
handler: 'StaleWhileRevalidate',
options: {
cacheName: 'static-assets',
expiration: {
maxEntries: 100,
maxAgeSeconds: 60 * 60 * 24 * 7 // 7 days
}
}
},
{
// Cache HTML pages with network-first for freshness
urlPattern: /\.html$/i,
handler: 'NetworkFirst',
options: {
cacheName: 'html-cache',
expiration: {
maxEntries: 20,
maxAgeSeconds: 60 * 60 * 24 // 1 day
},
networkTimeoutSeconds: 2
}
}
]
},
manifest: {
name: 'aitherboard - Decentralized Messageboard on Nostr',
short_name: 'aitherboard',
description: 'A decentralized messageboard built on the Nostr protocol. Create threads, comment, react, and zap in a censorship-resistant environment.',
theme_color: '#f1f5f9',
background_color: '#ffffff',
display: 'standalone',
icons: [
{
src: 'favicon.ico',
sizes: '64x64',
type: 'image/x-icon'
},
{
src: 'apple-touch-icon-180x180.png',
sizes: '180x180',
type: 'image/png',
purpose: 'any maskable'
},
{
src: 'apple-touch-icon-152x152.png',
sizes: '152x152',
type: 'image/png'
},
{
src: 'apple-touch-icon-144x144.png',
sizes: '144x144',
type: 'image/png'
},
{
src: 'apple-touch-icon-120x120.png',
sizes: '120x120',
type: 'image/png'
},
{
src: 'apple-touch-icon-114x114.png',
sizes: '114x114',
type: 'image/png'
}
]
},
devOptions: {
enabled: false,
suppressWarnings: true // Suppress service worker warnings in dev mode
}
}),
{
name: 'generate-healthz',
buildStart() {
try {
execSync('node scripts/generate-healthz.js', { stdio: 'inherit' });
} catch (error) {
console.warn('Failed to generate healthz.json:', error);
}
}
}
],
server: {
port: 5173,
strictPort: false,
fs: {
// Allow serving files from the project root (including static directory if needed)
allow: ['..']
}
},
build: {
target: 'esnext',
sourcemap: false,
manifest: false,
minify: 'terser',
terserOptions: {
compress: {
drop_console: ['log', 'debug'], // Remove console.log and console.debug in production, keep error/warn
passes: 2, // Multiple passes for better compression
}
},
rollupOptions: {
onwarn(warning, warn) {
// Suppress warning about highlight.js default import - it's used in reactive contexts that Vite can't detect
if (warning.message &&
typeof warning.message === 'string' &&
(warning.message.includes('highlight.js') || warning.message.includes('"default" is imported')) &&
(warning.message.includes('never used') || warning.message.includes('but never used'))) {
return;
}
warn(warning);
}
}
}
});