File size: 5,484 Bytes
98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c 20c5151 98ace4c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
// 📊 Script de Análise de Performance do Bundle
// Analisa o tamanho dos arquivos e identifica oportunidades de otimização
const fs = require('fs');
const path = require('path');
console.log('🔍 ANÁLISE DE PERFORMANCE DO BUNDLE\n');
console.log('═'.repeat(80));
// Função para calcular tamanho legível
function formatBytes(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
}
// Função para analisar arquivo
function analyzeFile(filePath) {
const stats = fs.statSync(filePath);
const content = fs.readFileSync(filePath, 'utf8');
return {
path: filePath,
size: stats.size,
sizeFormatted: formatBytes(stats.size),
lines: content.split('\n').length,
characters: content.length,
// Estimativa de tamanho gzipped (aproximadamente 30% do original para texto)
gzipEstimate: formatBytes(Math.round(stats.size * 0.3))
};
}
// Arquivos principais para análise
const filesToAnalyze = [
'public/app.js',
'public/styles.css',
'public/index.html',
'public/sw.js',
'public/manifest.json'
];
let totalSize = 0;
const results = [];
console.log('\n📁 ARQUIVOS PRINCIPAIS:\n');
filesToAnalyze.forEach(file => {
try {
const analysis = analyzeFile(file);
results.push(analysis);
totalSize += analysis.size;
console.log(`📄 ${path.basename(file)}`);
console.log(` Tamanho: ${analysis.sizeFormatted}`);
console.log(` Linhas: ${analysis.lines.toLocaleString()}`);
console.log(` Gzip (est.): ${analysis.gzipEstimate}`);
console.log('');
} catch (error) {
console.log(`⚠️ ${file} - Arquivo não encontrado`);
}
});
console.log('─'.repeat(80));
console.log(`\n📊 TOTAL: ${formatBytes(totalSize)}`);
console.log(`📦 GZIP ESTIMADO: ${formatBytes(Math.round(totalSize * 0.3))}`);
// Análise de app.js para identificar oportunidades
console.log('\n═'.repeat(80));
console.log('🔬 ANÁLISE DETALHADA DO app.js\n');
try {
const appJs = fs.readFileSync('public/app.js', 'utf8');
// Contar funções
const functionCount = (appJs.match(/function\s+\w+/g) || []).length;
const arrowFunctionCount = (appJs.match(/=>\s*{/g) || []).length;
const classCount = (appJs.match(/class\s+\w+/g) || []).length;
// Contar comentários
const commentLines = (appJs.match(/\/\/.+|\/\*[\s\S]*?\*\//g) || []).length;
// Contar imports/requires (se houver)
const imports = (appJs.match(/import\s+.+from|require\(.+\)/g) || []).length;
console.log(`📦 Classes: ${classCount}`);
console.log(`🔧 Funções: ${functionCount}`);
console.log(`➡️ Arrow Functions: ${arrowFunctionCount}`);
console.log(`💬 Comentários: ${commentLines}`);
console.log(`📥 Imports: ${imports}`);
// Análise de strings grandes (possíveis JSON embutidos)
const largeStrings = appJs.match(/['"`][\s\S]{500,}['"`]/g) || [];
if (largeStrings.length > 0) {
console.log(`\n⚠️ ${largeStrings.length} strings grandes encontradas (>500 chars)`);
console.log(` Considere mover para arquivos JSON externos`);
}
} catch (error) {
console.log('⚠️ Erro ao analisar app.js');
}
// Recomendações
console.log('\n═'.repeat(80));
console.log('💡 RECOMENDAÇÕES DE OTIMIZAÇÃO\n');
const recommendations = [];
if (totalSize > 300000) {
recommendations.push({
priority: 'ALTA',
issue: 'Bundle muito grande (>300KB)',
solution: 'Implementar code splitting e lazy loading'
});
}
if (results.find(r => r.path.includes('app.js') && r.size > 150000)) {
recommendations.push({
priority: 'ALTA',
issue: 'app.js muito grande (>150KB)',
solution: 'Dividir em módulos menores e carregar sob demanda'
});
}
if (results.find(r => r.path.includes('styles.css') && r.size > 50000)) {
recommendations.push({
priority: 'MÉDIA',
issue: 'styles.css grande (>50KB)',
solution: 'Remover CSS não utilizado com PurgeCSS'
});
}
recommendations.push({
priority: 'MÉDIA',
issue: 'Sem minificação',
solution: 'Implementar minificação com Terser (JS) e cssnano (CSS)'
});
recommendations.push({
priority: 'ALTA',
issue: 'Sem compressão Gzip/Brotli',
solution: 'Configurar compressão no servidor'
});
recommendations.push({
priority: 'BAIXA',
issue: 'Otimização de imagens',
solution: 'Converter SVGs para WebP quando apropriado'
});
recommendations.forEach((rec, index) => {
console.log(`${index + 1}. [${rec.priority}] ${rec.issue}`);
console.log(` 💡 ${rec.solution}\n`);
});
console.log('═'.repeat(80));
console.log('\n✅ Análise completa! Execute os scripts de otimização para melhorar o desempenho.\n');
// Salvar relatório em JSON
const report = {
timestamp: new Date().toISOString(),
files: results,
totalSize: totalSize,
totalSizeFormatted: formatBytes(totalSize),
gzipEstimate: formatBytes(Math.round(totalSize * 0.3)),
recommendations: recommendations
};
fs.writeFileSync('scripts/bundle-analysis.json', JSON.stringify(report, null, 2));
console.log('📄 Relatório salvo em: scripts/bundle-analysis.json\n');
|