codebase-asset-optimizer
Version:
Professional CLI development tool for optimizing and managing assets in codebases. Detects unused assets, optimizes images to WebP, optimizes videos, and automatically replaces asset references. GIFs are preserved unchanged to maintain animation functiona
170 lines ⢠7.78 kB
JavaScript
/**
* Performance Benchmark for codebase-asset-optimizer
* Shows users the real-world impact of asset optimization
*/
import fs from 'fs-extra';
import path from 'path';
import chalk from 'chalk';
import { execSync } from 'child_process';
const TEST_PROJECT_DIR = path.join(process.cwd(), 'test-project');
const PUBLIC_DIR = path.join(TEST_PROJECT_DIR, 'public');
async function getDirectorySize(dirPath) {
let totalSize = 0;
async function calculateSize(currentPath) {
const stats = await fs.stat(currentPath);
if (stats.isDirectory()) {
const files = await fs.readdir(currentPath);
for (const file of files) {
await calculateSize(path.join(currentPath, file));
}
}
else {
totalSize += stats.size;
}
}
if (await fs.pathExists(dirPath)) {
await calculateSize(dirPath);
}
return totalSize;
}
function formatBytes(bytes) {
if (bytes === 0)
return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
async function countAssets(dirPath) {
let images = 0;
let videos = 0;
if (await fs.pathExists(dirPath)) {
const items = await fs.readdir(dirPath, { withFileTypes: true });
for (const item of items) {
if (item.isDirectory()) {
const subCounts = await countAssets(path.join(dirPath, item.name));
images += subCounts.images;
videos += subCounts.videos;
}
else {
const ext = path.extname(item.name).toLowerCase();
if (['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'].includes(ext)) {
images++;
}
else if (['.mp4', '.webm', '.mov', '.avi', '.mkv'].includes(ext)) {
videos++;
}
}
}
}
return { images, videos };
}
async function runBenchmark() {
console.log(chalk.cyan('\nā” Asset Optimization Performance Benchmark'));
console.log(chalk.cyan('=============================================\n'));
// Check if test project exists - handle different execution contexts
let testProjectDir = TEST_PROJECT_DIR;
// If running from test-project directory, use current directory
if (process.cwd().endsWith('test-project')) {
testProjectDir = process.cwd();
}
// If running from project root, use test-project subdirectory
else if (await fs.pathExists(TEST_PROJECT_DIR)) {
testProjectDir = TEST_PROJECT_DIR;
}
// If neither exists, exit gracefully
else {
console.log(chalk.red('ā Test project not found. Expected to find test assets.'));
console.log(chalk.gray(' Run this from the project root or test-project directory.'));
return;
}
const publicDir = path.join(testProjectDir, 'public');
if (!await fs.pathExists(publicDir)) {
console.log(chalk.red('ā Public directory not found in test project.'));
return;
}
console.log(chalk.blue('š Analyzing current state...'));
// Get baseline metrics
const beforeSize = await getDirectorySize(publicDir);
const assetCounts = await countAssets(publicDir);
console.log(chalk.white('š Current Asset Inventory:'));
console.log(chalk.gray(` Images: ${assetCounts.images}`));
console.log(chalk.gray(` Videos: ${assetCounts.videos}`));
console.log(chalk.gray(` Total size: ${formatBytes(beforeSize)}`));
// Run audit to get optimization potential
console.log(chalk.blue('\nš Analyzing optimization potential...'));
try {
const auditOutput = execSync('npm run audit:assets test-project', {
encoding: 'utf8',
stdio: 'pipe'
});
// Extract optimization info from audit output
const optimizableMatch = auditOutput.match(/Optimizable: (\d+) \(([^)]+)\)/);
if (optimizableMatch) {
const optimizableCount = optimizableMatch[1];
const optimizableSize = optimizableMatch[2];
console.log(chalk.green(`ā
Found ${optimizableCount} assets that can be optimized`));
console.log(chalk.gray(` Current size: ${optimizableSize}`));
}
}
catch (error) {
console.log(chalk.yellow('ā ļø Could not run audit, but continuing...'));
}
// Run dry-run to show what would happen
console.log(chalk.blue('\nš® Simulating optimization (dry-run)...'));
try {
const dryRunOutput = execSync('npm run optimize:assets:dry test-project', {
encoding: 'utf8',
stdio: 'pipe'
});
// Extract potential savings
const savingsMatch = dryRunOutput.match(/Estimated savings: (\d+)-(\d+)%/);
if (savingsMatch) {
const minSavings = parseInt(savingsMatch[1]);
const maxSavings = parseInt(savingsMatch[2]);
const estimatedMinSize = beforeSize * (1 - maxSavings / 100);
const estimatedMaxSize = beforeSize * (1 - minSavings / 100);
console.log(chalk.green('š Optimization Impact Projection:'));
console.log(chalk.white(` Current total: ${formatBytes(beforeSize)}`));
console.log(chalk.green(` Estimated after: ${formatBytes(estimatedMinSize)} - ${formatBytes(estimatedMaxSize)}`));
console.log(chalk.green(` Potential savings: ${formatBytes(beforeSize - estimatedMaxSize)} - ${formatBytes(beforeSize - estimatedMinSize)}`));
console.log(chalk.green(` Reduction: ${minSavings}% - ${maxSavings}%`));
}
}
catch (error) {
console.log(chalk.yellow('ā ļø Could not run dry-run simulation'));
}
// Show performance benefits
console.log(chalk.blue('\nš Performance Benefits:'));
console.log(chalk.white(' š± Mobile Performance:'));
console.log(chalk.green(' ⢠Faster page loads on slow connections'));
console.log(chalk.green(' ⢠Reduced data usage for users'));
console.log(chalk.green(' ⢠Better Core Web Vitals scores'));
console.log(chalk.white('\n š Web Performance:'));
console.log(chalk.green(' ⢠Improved LCP (Largest Contentful Paint)'));
console.log(chalk.green(' ⢠Better SEO rankings'));
console.log(chalk.green(' ⢠Reduced CDN/hosting costs'));
console.log(chalk.white('\n š¾ Storage Benefits:'));
console.log(chalk.green(' ⢠Smaller repository size'));
console.log(chalk.green(' ⢠Faster CI/CD deployments'));
console.log(chalk.green(' ⢠Lower bandwidth costs'));
// Show commands to take action
console.log(chalk.blue('\nšÆ Take Action:'));
console.log(chalk.cyan(' 1. Review what would be optimized:'));
console.log(chalk.white(' npm run optimize:assets:dry test-project'));
console.log(chalk.cyan('\n 2. Apply optimizations safely:'));
console.log(chalk.white(' npm run optimize:assets test-project'));
console.log(chalk.cyan('\n 3. Use for your real project:'));
console.log(chalk.white(' npm run audit:assets'));
console.log(chalk.white(' npm run optimize:assets:dry'));
console.log(chalk.white(' npm run optimize:assets'));
console.log(chalk.green('\n⨠Start optimizing and boost your app performance!'));
}
// Run the benchmark
runBenchmark().catch((error) => {
console.error(chalk.red('\nā Benchmark failed!'));
console.error(chalk.red(`Error: ${error.message}`));
process.exit(1);
});
//# sourceMappingURL=benchmark.js.map