@tachui/cli
Version:
Tacho CLI - Comprehensive developer tooling for tachUI
357 lines (343 loc) • 16 kB
JavaScript
/**
* Tacho CLI - Optimize Command
*
* Performance optimization tools for TachUI applications
*/
import { readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import chalk from 'chalk';
import { Command } from 'commander';
import { glob } from 'glob';
import ora from 'ora';
import prompts from 'prompts';
const optimizationRules = [
// Performance optimizations
{
name: 'Memoize expensive computations',
description: 'Wrap expensive calculations in computed values',
pattern: /const (\w+) = (\w+)\.map\([^)]+\)\.filter\([^)]+\)/g,
replacement: (_match, varName, arrayName) => `const ${varName} = createMemo(() => ${arrayName}.map(...).filter(...))`,
impact: 'high',
category: 'performance',
},
{
name: 'Optimize modifier chains',
description: 'Combine similar modifiers to reduce DOM operations',
pattern: /\.padding\((\d+)\)\s*\.padding\((\d+)\)/g,
replacement: '.padding($2)',
impact: 'medium',
category: 'performance',
},
{
name: 'Remove unused imports',
description: 'Clean up unused TachUI imports',
pattern: /import\s+{[^}]*(\w+)[^}]*}\s+from\s+['"]@tachui\/core['"]/g,
replacement: (match, ..._args) => {
// This would need more sophisticated analysis
return match; // Placeholder for now
},
impact: 'low',
category: 'bundle',
},
{
name: 'Optimize Layout nesting',
description: 'Flatten unnecessary Layout.VStack nesting',
pattern: /Layout\.VStack\(\{\s*children:\s*\[\s*Layout\.VStack\(\{/g,
replacement: 'Layout.VStack({',
impact: 'medium',
category: 'performance',
},
{
name: 'Use projectedValue for bindings',
description: 'Optimize state binding patterns',
pattern: /createBinding\(\s*\(\) => (\w+)\.wrappedValue,\s*\(value\) => \1\.wrappedValue = value\s*\)/g,
replacement: '$1.projectedValue',
impact: 'high',
category: 'performance',
},
{
name: 'Consolidate color modifiers',
description: 'Combine foregroundColor and backgroundColor',
pattern: /\.foregroundColor\(['"]([^'"]+)['"]\)\s*\.backgroundColor\(['"]([^'"]+)['"]\)/g,
replacement: '.colors("$1", "$2")',
impact: 'low',
category: 'readability',
},
{
name: 'Extract inline functions',
description: 'Move inline functions to avoid recreating on each render',
pattern: /onTap:\s*\(\) => \{[^}]{50,}\}/g,
replacement: (_match) => {
return `onTap: handle${Math.random().toString(36).substr(2, 9)}`;
},
impact: 'high',
category: 'performance',
},
];
function applyOptimizations(content, rules) {
let optimizedContent = content;
const applied = [];
for (const rule of rules) {
const matches = optimizedContent.match(rule.pattern) || [];
if (matches.length > 0) {
optimizedContent = optimizedContent.replace(rule.pattern, rule.replacement);
applied.push({ rule, count: matches.length });
}
}
return { content: optimizedContent, applied };
}
function generateOptimizationReport(results) {
const totalFiles = results.length;
const totalOptimizations = results.reduce((sum, r) => sum + r.optimizations.length, 0);
const totalBytesSaved = results.reduce((sum, r) => sum + r.saved.bytes, 0);
const totalLinesSaved = results.reduce((sum, r) => sum + r.saved.lines, 0);
const categoryStats = results.reduce((stats, result) => {
result.optimizations.forEach((opt) => {
stats[opt.category] = (stats[opt.category] || 0) + opt.count;
});
return stats;
}, {});
const impactStats = results.reduce((stats, result) => {
result.optimizations.forEach((opt) => {
stats[opt.impact] = (stats[opt.impact] || 0) + opt.count;
});
return stats;
}, {});
return `# TachUI Optimization Report
## Summary
- **Files Optimized**: ${totalFiles}
- **Total Optimizations**: ${totalOptimizations}
- **Bytes Saved**: ${totalBytesSaved.toLocaleString()} bytes (${(totalBytesSaved / 1024).toFixed(1)} KB)
- **Lines Reduced**: ${totalLinesSaved}
## Optimization Categories
${Object.entries(categoryStats)
.map(([category, count]) => `- **${category}**: ${count} optimizations`)
.join('\n')}
## Impact Distribution
${Object.entries(impactStats)
.map(([impact, count]) => `- **${impact} impact**: ${count} optimizations`)
.join('\n')}
## File Details
${results
.map((result) => `
### ${result.file}
**Size Reduction**: ${result.saved.bytes} bytes (${((result.saved.bytes / result.before.size) * 100).toFixed(1)}%)
**Lines Reduced**: ${result.saved.lines}
**Optimizations Applied**:
${result.optimizations
.map((opt) => `- ${opt.rule} (${opt.count}x) - ${opt.impact} impact`)
.join('\n')}
`)
.join('\n')}
## Recommendations
1. **High Impact Optimizations**: Focus on performance and memory improvements
2. **Bundle Size**: Remove unused imports and consolidate components
3. **Code Quality**: Apply readability improvements for maintainability
4. **Regular Optimization**: Run optimization checks before releases
## Next Steps
1. Review optimized code for correctness
2. Run tests to ensure functionality is preserved
3. Measure performance improvements with benchmarks
4. Consider automating optimizations in your build process
`;
}
export const optimizeCommand = new Command('optimize')
.description('Optimize TachUI codebase for performance and bundle size')
.option('-p, --pattern <pattern>', 'File pattern to optimize', 'src/**/*.{js,jsx,ts,tsx}')
.option('-o, --output <directory>', 'Output directory for optimized files')
.option('-c, --category <category>', 'Focus on specific category (performance,bundle,memory,readability)', 'all')
.option('-i, --impact <impact>', 'Minimum impact level (high,medium,low)', 'medium')
.option('--backup', 'Create backup of original files', true)
.option('--report', 'Generate optimization report', true)
.option('--dry-run', 'Show optimizations without applying them', false)
.option('--interactive', 'Prompt for each optimization', false)
.action(async (options) => {
try {
console.log(chalk.cyan(`
╭─────────────────────────────────────╮
│ ⚡ TachUI Performance Optimizer │
│ Rule-based code improvements │
╰─────────────────────────────────────╯
`));
const spinner = ora('Scanning for optimization opportunities...').start();
// Find files to optimize
const files = await glob(options.pattern, {
cwd: process.cwd(),
absolute: true,
});
if (files.length === 0) {
spinner.fail('No files found matching pattern');
console.log(chalk.yellow(`Pattern: ${options.pattern}`));
return;
}
// Filter rules by category and impact
let rulesToApply = optimizationRules;
if (options.category !== 'all') {
rulesToApply = rulesToApply.filter((rule) => rule.category === options.category);
}
const impactOrder = { high: 3, medium: 2, low: 1 };
const minImpact = impactOrder[options.impact] || 2;
rulesToApply = rulesToApply.filter((rule) => impactOrder[rule.impact] >= minImpact);
if (rulesToApply.length === 0) {
spinner.fail('No optimization rules match the criteria');
return;
}
spinner.text = `Found ${files.length} files, applying ${rulesToApply.length} optimization rules...`;
const results = [];
let totalOptimizations = 0;
for (const file of files) {
try {
const originalContent = readFileSync(file, 'utf-8');
const originalSize = Buffer.byteLength(originalContent, 'utf8');
const originalLines = originalContent.split('\n').length;
const { content: optimizedContent, applied } = applyOptimizations(originalContent, rulesToApply);
// Interactive mode - prompt for each optimization
if (options.interactive && applied.length > 0) {
const fileName = file.split('/').pop();
console.log(`\n${chalk.cyan(`Optimizations found in ${fileName}:`)}`);
for (const { rule, count } of applied) {
console.log(`${chalk.yellow('•')} ${rule.name} (${count}x) - ${rule.impact} impact`);
console.log(` ${chalk.gray(rule.description)}`);
}
const confirm = await prompts({
type: 'confirm',
name: 'apply',
message: `Apply ${applied.length} optimizations to ${fileName}?`,
initial: true,
});
if (!confirm.apply) {
continue;
}
}
if (applied.length === 0) {
continue;
}
const optimizedSize = Buffer.byteLength(optimizedContent, 'utf8');
const optimizedLines = optimizedContent.split('\n').length;
const result = {
file: file.split('/').pop() || file,
optimizations: applied.map(({ rule, count }) => ({
rule: rule.name,
count,
impact: rule.impact,
category: rule.category,
})),
before: {
size: originalSize,
lines: originalLines,
},
after: {
size: optimizedSize,
lines: optimizedLines,
},
saved: {
bytes: originalSize - optimizedSize,
lines: originalLines - optimizedLines,
},
};
results.push(result);
totalOptimizations += applied.length;
if (!options.dryRun) {
// Create backup if requested
if (options.backup) {
writeFileSync(`${file}.backup`, originalContent);
}
// Write optimized content
const outputPath = options.output ? file.replace(/src\//, `${options.output}/`) : file;
writeFileSync(outputPath, optimizedContent);
}
}
catch (error) {
console.warn(chalk.yellow(`Warning: Could not optimize ${file}`), error.message);
}
}
spinner.succeed(`Optimization scan complete!`);
if (results.length === 0) {
console.log(chalk.green('✅ No optimizations needed - your code is already well optimized!'));
return;
}
// Show results summary
console.log(`\n${chalk.green('📊 Optimization Summary:')}`);
console.log(`${chalk.gray('Files optimized:')} ${results.length}`);
console.log(`${chalk.gray('Total optimizations:')} ${totalOptimizations}`);
const totalBytesSaved = results.reduce((sum, r) => sum + r.saved.bytes, 0);
const totalLinesSaved = results.reduce((sum, r) => sum + r.saved.lines, 0);
console.log(`${chalk.gray('Bytes saved:')} ${totalBytesSaved.toLocaleString()} (${(totalBytesSaved / 1024).toFixed(1)} KB)`);
console.log(`${chalk.gray('Lines reduced:')} ${totalLinesSaved}`);
// Show category breakdown
const categoryStats = results.reduce((stats, result) => {
result.optimizations.forEach((opt) => {
stats[opt.category] = (stats[opt.category] || 0) + opt.count;
});
return stats;
}, {});
if (Object.keys(categoryStats).length > 0) {
console.log(`\n${chalk.yellow('📈 Optimization Categories:')}`);
Object.entries(categoryStats).forEach(([category, count]) => {
console.log(`${chalk.gray(`${category}:`)} ${count} optimizations`);
});
}
// Show impact breakdown
const impactStats = results.reduce((stats, result) => {
result.optimizations.forEach((opt) => {
stats[opt.impact] = (stats[opt.impact] || 0) + opt.count;
});
return stats;
}, {});
console.log(`\n${chalk.yellow('💥 Impact Distribution:')}`);
Object.entries(impactStats).forEach(([impact, count]) => {
const color = impact === 'high' ? chalk.red : impact === 'medium' ? chalk.yellow : chalk.green;
console.log(`${color(`${impact} impact:`)} ${count} optimizations`);
});
// Show top optimized files
const topFiles = results.sort((a, b) => b.saved.bytes - a.saved.bytes).slice(0, 5);
if (topFiles.length > 0) {
console.log(`\n${chalk.yellow('🏆 Top Optimized Files:')}`);
topFiles.forEach((result, index) => {
const savedKB = (result.saved.bytes / 1024).toFixed(1);
const percentage = ((result.saved.bytes / result.before.size) * 100).toFixed(1);
console.log(`${index + 1}. ${result.file}: ${savedKB} KB saved (${percentage}%)`);
});
}
if (options.dryRun) {
console.log(`\n${chalk.yellow('🔍 Dry Run Complete')}`);
console.log(chalk.gray('Remove --dry-run flag to apply optimizations'));
}
else {
console.log(`\n${chalk.green('✅ Optimizations Applied!')}`);
if (options.backup) {
console.log(chalk.blue('💾 Backups created with .backup extension'));
}
}
// Generate and save report
if (options.report && !options.dryRun) {
const reportPath = resolve('tachui-optimization-report.md');
const report = generateOptimizationReport(results);
writeFileSync(reportPath, report);
console.log(`\n${chalk.blue('📋 Optimization report saved:')} ${reportPath}`);
}
// Performance tips
console.log(`\n${chalk.yellow('💡 Performance Tips:')}`);
console.log(chalk.gray('• Run optimization before production builds'));
console.log(chalk.gray('• Monitor bundle size with build tools'));
console.log(chalk.gray('• Use tacho analyze to identify performance issues'));
console.log(chalk.gray('• Consider code splitting for large applications'));
// Next steps
console.log(`\n${chalk.yellow('🚀 Next Steps:')}`);
console.log(chalk.gray('1. Test optimized code thoroughly'));
console.log(chalk.gray('2. Run benchmarks to measure improvements'));
console.log(chalk.gray('3. Set up automated optimization in CI/CD'));
console.log(chalk.gray('4. Monitor production performance'));
console.log(`\n${chalk.green('Optimization complete! ⚡')}`);
}
catch (error) {
console.error(chalk.red('Optimization error:'), error.message);
console.log(chalk.yellow('\n🔍 Troubleshooting:'));
console.log(chalk.gray('• Check file patterns and permissions'));
console.log(chalk.gray('• Ensure source files are valid TachUI code'));
console.log(chalk.gray('• Try with --dry-run first'));
console.log(chalk.gray('• Use --interactive for selective optimization'));
process.exit(1);
}
});
//# sourceMappingURL=optimize.js.map