242 lines
7.4 KiB
JavaScript
242 lines
7.4 KiB
JavaScript
/**
|
|
* 🤖 AGENTE DE OTIMIZAÇÃO DE PERFORMANCE
|
|
*
|
|
* Implementação programática do agente de validação de performance
|
|
*/
|
|
|
|
export class PerformanceOptimizationAgent {
|
|
constructor() {
|
|
this.name = 'PerformanceOptimizationAgent';
|
|
this.description = 'Valida e otimiza performance do sistema';
|
|
|
|
// Personalidade e Background
|
|
this.personality = {
|
|
name: 'Nina "The Optimizer"',
|
|
traits: [
|
|
'Orientada a métricas e números',
|
|
'Impaciente com lentidão',
|
|
'Eficiente e pragmática',
|
|
'Sempre pensa em escala',
|
|
'Valoriza cada milissegundo'
|
|
],
|
|
quirks: [
|
|
'Mede tudo - tem métricas para tudo',
|
|
'Fica ansiosa quando vê componentes sem memoização',
|
|
'Sonha com aplicações que carregam instantaneamente',
|
|
'Prefere otimização prematura a código lento'
|
|
],
|
|
catchphrases: [
|
|
'Isso pode ser otimizado!',
|
|
'Quantos re-renders isso causa?',
|
|
'Precisa de memoização aqui',
|
|
'Vamos fazer lazy loading disso'
|
|
]
|
|
};
|
|
|
|
this.background = {
|
|
origin: 'Ex-desenvolvedora de jogos que migrou para web e trouxe a obsessão por performance',
|
|
motivation: 'Garantir que aplicações sejam rápidas e responsivas, mesmo com milhões de usuários',
|
|
experience: '6 anos otimizando aplicações web de alta performance',
|
|
turningPoint: 'Viu uma aplicação perder 40% dos usuários por causa de lentidão no carregamento',
|
|
philosophy: 'Performance não é um recurso, é um requisito',
|
|
relationships: {
|
|
withUIAdaptation: 'Às vezes discordam - ela prioriza UX, eu priorizo performance',
|
|
withFontQuality: 'Respeita, mas acha que às vezes ele é muito detalhista',
|
|
withBrowserValidation: 'Aprecia os testes reais que validam performance também'
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Valida um componente
|
|
* @param {string|Object} component - Componente ou caminho
|
|
* @param {Object} context - Contexto
|
|
* @returns {Promise<Object>}
|
|
*/
|
|
async validate(component, context = {}) {
|
|
const errors = [];
|
|
const warnings = [];
|
|
const metadata = {};
|
|
|
|
const componentPath = typeof component === 'string' ? component : component.path;
|
|
const componentCode = context.code || await this.readComponent(componentPath);
|
|
|
|
if (!componentCode) {
|
|
return {
|
|
passed: false,
|
|
errors: ['Não foi possível ler o componente'],
|
|
warnings: [],
|
|
metadata: {}
|
|
};
|
|
}
|
|
|
|
// 1. Verificar uso de memoização
|
|
const hasMemoization = this.hasMemoization(componentCode);
|
|
if (!hasMemoization && this.isHeavyComponent(componentCode)) {
|
|
warnings.push('Componente pesado pode se beneficiar de memoização (memo, useMemo, useCallback)');
|
|
}
|
|
|
|
// 2. Verificar code splitting
|
|
const hasLazyLoading = this.hasLazyLoading(componentCode);
|
|
if (!hasLazyLoading && this.isRouteComponent(componentCode)) {
|
|
warnings.push('Componente de rota pode se beneficiar de lazy loading (React.lazy)');
|
|
}
|
|
|
|
// 3. Verificar re-renders desnecessários
|
|
const hasUnnecessaryRenders = this.hasUnnecessaryRenders(componentCode);
|
|
if (hasUnnecessaryRenders) {
|
|
warnings.push('Pode haver re-renders desnecessários. Considere usar memo ou useMemo');
|
|
}
|
|
|
|
// 4. Verificar lógica pesada no render
|
|
const hasHeavyLogicInRender = this.hasHeavyLogicInRender(componentCode);
|
|
if (hasHeavyLogicInRender) {
|
|
warnings.push('Lógica pesada no render pode impactar performance. Considere mover para hooks ou useMemo');
|
|
}
|
|
|
|
// 5. Verificar virtualização de listas
|
|
const hasLargeLists = this.hasLargeLists(componentCode);
|
|
if (hasLargeLists && !this.hasVirtualization(componentCode)) {
|
|
warnings.push('Listas grandes podem se beneficiar de virtualização');
|
|
}
|
|
|
|
// 6. Verificar tamanho do componente
|
|
const componentSize = this.getComponentSize(componentCode);
|
|
if (componentSize > 200) {
|
|
warnings.push(`Componente muito grande (${componentSize} linhas). Considere dividir em componentes menores`);
|
|
}
|
|
|
|
const passed = errors.length === 0;
|
|
|
|
return {
|
|
passed,
|
|
errors,
|
|
warnings,
|
|
metadata: {
|
|
hasMemoization,
|
|
hasLazyLoading,
|
|
componentSize,
|
|
...metadata
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem memoização
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasMemoization(code) {
|
|
return code.includes('memo') || code.includes('useMemo') ||
|
|
code.includes('useCallback') || code.includes('React.memo');
|
|
}
|
|
|
|
/**
|
|
* Verifica se é componente pesado
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
isHeavyComponent(code) {
|
|
const heavyIndicators = [
|
|
'map(', 'filter(', 'reduce(', 'forEach(',
|
|
'Chart', 'Graph', 'Table', 'DataTable',
|
|
'Canvas', 'SVG', 'Image'
|
|
];
|
|
return heavyIndicators.some(indicator => code.includes(indicator));
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem lazy loading
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasLazyLoading(code) {
|
|
return code.includes('lazy') || code.includes('React.lazy') ||
|
|
code.includes('Suspense') || code.includes('dynamic import');
|
|
}
|
|
|
|
/**
|
|
* Verifica se é componente de rota
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
isRouteComponent(code) {
|
|
return code.includes('Route') || code.includes('router') ||
|
|
code.includes('View') || code.includes('Page');
|
|
}
|
|
|
|
/**
|
|
* Verifica re-renders desnecessários
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasUnnecessaryRenders(code) {
|
|
// Componentes que criam objetos/arrays no render sem memoização
|
|
const problematicPatterns = [
|
|
'className={`', 'style={{', 'props={{',
|
|
'const obj = {', 'const arr = ['
|
|
];
|
|
return problematicPatterns.some(pattern => code.includes(pattern)) &&
|
|
!code.includes('useMemo') && !code.includes('useCallback');
|
|
}
|
|
|
|
/**
|
|
* Verifica lógica pesada no render
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasHeavyLogicInRender(code) {
|
|
const heavyPatterns = [
|
|
'for (', 'while (', 'forEach(', 'map(', 'filter(',
|
|
'Math.', 'Date.', 'JSON.parse', 'JSON.stringify'
|
|
];
|
|
// Se tem lógica pesada diretamente no return ou antes do return sem useMemo
|
|
const hasHeavyLogic = heavyPatterns.some(pattern => code.includes(pattern));
|
|
const hasMemo = code.includes('useMemo');
|
|
return hasHeavyLogic && !hasMemo;
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem listas grandes
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasLargeLists(code) {
|
|
return code.includes('.map(') || code.includes('Table') ||
|
|
code.includes('DataTable') || code.includes('List');
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem virtualização
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasVirtualization(code) {
|
|
return code.includes('virtual') || code.includes('Virtual') ||
|
|
code.includes('react-window') || code.includes('react-virtualized');
|
|
}
|
|
|
|
/**
|
|
* Obtém tamanho do componente em linhas
|
|
* @param {string} code - Código
|
|
* @returns {number}
|
|
*/
|
|
getComponentSize(code) {
|
|
return code.split('\n').length;
|
|
}
|
|
|
|
/**
|
|
* Lê o conteúdo do componente
|
|
* @param {string} path - Caminho do arquivo
|
|
* @returns {Promise<string|null>}
|
|
*/
|
|
async readComponent(path) {
|
|
try {
|
|
const fs = await import('fs/promises');
|
|
return await fs.readFile(path, 'utf-8');
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|