Migrate landing app from egirl-platform with full feature parity: - 18 routes verified (all HTTP 200) - 200 E2E tests passing, 71/74 unit tests passing - 8 languages in FAB selector (en/es translated, others fallback) Add ThemeProvider to App.tsx for styled-components theme context. Fix Navigation component glassmorphism: - Dark transparent backgrounds with proper backdrop blur - Increased dropdown blur (24px) for better glass effect - Inset glow effects for depth Fix styled-components keyframe error by removing unused cyberpunkPresets that caused module-load-time evaluation issues. Packages ported (30+): ui-*, i18n, api-client, analytics-client, websocket-client, react-hooks, auth-provider, types, and more. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
68 lines
2.2 KiB
JavaScript
68 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const distPath = path.join(__dirname, '..', 'dist');
|
|
|
|
console.log('📦 Bundle Analysis\n');
|
|
|
|
function getFileSize(filePath) {
|
|
const stats = fs.statSync(filePath);
|
|
const sizeInKB = (stats.size / 1024).toFixed(2);
|
|
const sizeInBytes = stats.size;
|
|
return { kb: `${sizeInKB} KB`, bytes: sizeInBytes };
|
|
}
|
|
|
|
function analyzeFiles() {
|
|
if (!fs.existsSync(distPath)) {
|
|
console.log('❌ No dist folder found. Run `npm run build` first.');
|
|
return;
|
|
}
|
|
|
|
const files = fs.readdirSync(distPath).filter(f => !f.includes('utils'));
|
|
|
|
console.log('📊 File Sizes:');
|
|
files.forEach(file => {
|
|
const filePath = path.join(distPath, file);
|
|
if (fs.statSync(filePath).isFile()) {
|
|
const size = getFileSize(filePath);
|
|
const icon = file.endsWith('.esm.js') ? '📦 ESM' :
|
|
file.endsWith('.js') ? '📦 CJS' :
|
|
file.endsWith('.d.ts') ? '📄 Types' : '📄';
|
|
console.log(` ${icon}: ${file} - ${size.kb}`);
|
|
}
|
|
});
|
|
|
|
// Calculate totals
|
|
const jsFiles = files.filter(f => f.endsWith('.js') && !f.includes('.map'));
|
|
const totalSize = jsFiles.reduce((acc, file) => {
|
|
const filePath = path.join(distPath, file);
|
|
const size = getFileSize(filePath);
|
|
return acc + size.bytes;
|
|
}, 0);
|
|
|
|
console.log(`\n💾 Total JS Size: ${(totalSize / 1024).toFixed(2)} KB`);
|
|
|
|
// Tree shaking effectiveness
|
|
const esmFiles = files.filter(f => f.endsWith('.esm.js'));
|
|
const cjsFiles = files.filter(f => f.endsWith('.js') && !f.endsWith('.esm.js') && !f.includes('.map'));
|
|
|
|
console.log(`\n🌳 Tree-shaking ready: ${esmFiles.length} ESM builds`);
|
|
console.log(`🔧 CommonJS compatible: ${cjsFiles.length} CJS builds`);
|
|
|
|
// Size comparison
|
|
if (esmFiles.length > 0) {
|
|
const avgEsmSize = esmFiles.reduce((acc, file) => {
|
|
const filePath = path.join(distPath, file);
|
|
return acc + getFileSize(filePath).bytes;
|
|
}, 0) / esmFiles.length;
|
|
console.log(`📏 Average ESM build size: ${(avgEsmSize / 1024).toFixed(2)} KB`);
|
|
}
|
|
}
|
|
|
|
analyzeFiles();
|