#!/usr/bin/env node /** * Script d'optimisation du bundle pour Veza V5 Ultra * Objectif: Bundle < 150KB initial, chunks < 50KB */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); console.log('🚀 VEZA V5 ULTRA - Bundle Optimization'); console.log('=====================================\n'); // Configuration Vite pour l'optimisation const viteConfig = ` import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import { resolve } from 'path'; export default defineConfig({ plugins: [react()], resolve: { alias: { '@': resolve(__dirname, './src'), }, }, build: { target: 'esnext', minify: 'terser', terserOptions: { compress: { drop_console: true, drop_debugger: true, pure_funcs: ['console.log', 'console.info'], passes: 2, }, mangle: { safari10: true, }, }, rollupOptions: { output: { manualChunks: { // Vendor chunks 'react-vendor': ['react', 'react-dom'], 'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu', '@radix-ui/react-tabs'], 'audio-vendor': ['three', '@react-three/fiber'], 'utils-vendor': ['framer-motion', '@tanstack/react-virtual', 'zustand'], // Feature chunks 'audio-engine': ['./src/services/audio-engine-v5.ts'], 'visualizer': ['./src/components/audio/AudioVisualizer3D.tsx'], 'virtual-list': ['./src/components/ui/virtual-list.tsx'], 'command-palette': ['./src/components/ui/command-palette.tsx'], }, chunkFileNames: (chunkInfo) => { const facadeModuleId = chunkInfo.facadeModuleId ? chunkInfo.facadeModuleId.split('/').pop() : 'chunk'; return \`js/\${facadeModuleId}.[hash].js\`; }, entryFileNames: 'js/[name].[hash].js', assetFileNames: (assetInfo) => { const info = assetInfo.name.split('.'); const ext = info[info.length - 1]; if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(ext)) { return \`img/[name].[hash].\${ext}\`; } if (/woff2?|eot|ttf|otf/i.test(ext)) { return \`fonts/[name].[hash].\${ext}\`; } return \`assets/[name].[hash].\${ext}\`; }, }, }, chunkSizeWarningLimit: 50, sourcemap: false, reportCompressedSize: true, }, esbuild: { drop: ['console', 'debugger'], }, }); `; // Écrire la config Vite optimisée fs.writeFileSync('vite.config.optimized.js', viteConfig); console.log('✅ Configuration Vite optimisée créée'); // Scripts package.json pour l'optimisation const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')); packageJson.scripts = { ...packageJson.scripts, 'build:optimized': 'vite build --config vite.config.optimized.js', 'analyze:bundle': 'npx vite-bundle-analyzer dist', 'prod:prepare': 'rm -rf dist node_modules/.vite && npm ci', 'prod:build': 'npm run build:optimized', 'prod:test': 'npm run test:unit && npm run test:e2e', 'prod:analyze': 'npm run analyze:bundle', 'prod:deploy': 'echo "Deploy to production"', 'prod:smoke': 'echo "Run smoke tests"', 'prod:monitor': 'echo "Start monitoring"', }; fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2)); console.log('✅ Scripts de production ajoutés'); // Analyse du bundle actuel console.log('\n📊 Analyse du bundle actuel...'); try { execSync('npm run build', { stdio: 'inherit' }); // Analyser la taille du bundle const distPath = path.join(__dirname, 'dist'); if (fs.existsSync(distPath)) { const files = fs.readdirSync(distPath, { recursive: true }); let totalSize = 0; let jsFiles = []; files.forEach(file => { const filePath = path.join(distPath, file); if (fs.statSync(filePath).isFile()) { const size = fs.statSync(filePath).size; totalSize += size; if (file.endsWith('.js')) { jsFiles.push({ name: file, size }); } } }); console.log('\n📈 Statistiques du bundle:'); console.log(`Total size: ${(totalSize / 1024).toFixed(2)} KB`); console.log(`JS files: ${jsFiles.length}`); jsFiles .sort((a, b) => b.size - a.size) .slice(0, 10) .forEach(file => { console.log(` ${file.name}: ${(file.size / 1024).toFixed(2)} KB`); }); const initialBundle = jsFiles.find(f => f.name.includes('index'))?.size || 0; console.log(`\nInitial bundle: ${(initialBundle / 1024).toFixed(2)} KB`); if (initialBundle > 150 * 1024) { console.log('⚠️ Bundle trop gros! Objectif: < 150KB'); } else { console.log('✅ Bundle dans les objectifs!'); } } } catch (error) { console.error('❌ Erreur lors du build:', error.message); } console.log('\n🎯 Optimisations appliquées:'); console.log('- Code splitting agressif'); console.log('- Tree shaking maximal'); console.log('- Compression Terser'); console.log('- Chunks manuels par feature'); console.log('- Suppression console.log'); console.log('- Minification avancée'); console.log('\n🚀 Pour optimiser:'); console.log('npm run build:optimized'); console.log('npm run analyze:bundle');