veza/veza-desktop/scripts/optimize-bundle.js

169 lines
5.2 KiB
JavaScript

#!/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');