/**
* Optimized Build Script
* ----------------------
* This script runs a sequence of optimizations before building the Next.js app:
* 1. Optimizes images (resize, compress, convert to modern formats)
* 2. Analyzes and reduces unused JavaScript
* 3. Optimizes CSS
* 4. Runs the production build
*/
const { execSync } = require('child_process');
const path = require('path');
const fs = require('fs');
// Check if running in CI environment (like Vercel)
const isCI = process.env.CI === 'true' || process.env.VERCEL === '1';
console.log('๐ Starting optimized build process...');
console.log(isCI ? 'Running in CI environment (Vercel)' : 'Running in local environment');
// Create directory for build reports
const REPORTS_DIR = path.join(__dirname, '../build-reports');
if (!fs.existsSync(REPORTS_DIR)) {
fs.mkdirSync(REPORTS_DIR, { recursive: true });
}
// Utility to run commands and handle errors
function runCommand(command, name) {
console.log(`\n๐ Running ${name}...`);
try {
execSync(command, { stdio: 'inherit' });
console.log(`โ
${name} completed successfully`);
return true;
} catch (error) {
console.error(`โ ${name} failed:`, error.message);
return false;
}
}
// Conditional execution based on environment
if (!isCI) {
// 1. Install required dependencies if they don't exist
console.log('\n๐ฆ Checking build dependencies...');
try {
// Check if sharp and glob are installed
require.resolve('sharp');
require.resolve('glob');
console.log('โ
All dependencies installed');
} catch (error) {
console.log('๐ Installing missing dependencies...');
runCommand('npm install --save-dev sharp glob', 'Install dependencies');
}
// 2. Run Image Optimization - Skip in CI environment
runCommand('node scripts/optimize-images.js', 'Image Optimization');
// 3. Analyze bundle size - Skip in CI environment
const shouldAnalyze = process.env.ANALYZE === 'true';
if (shouldAnalyze) {
console.log('\n๐ Analyzing initial bundle size...');
runCommand(
'ANALYZE=true next build',
'Bundle analysis'
);
}
}
// 4. Run Next.js production build with all optimizations
console.log('\n๐๏ธ Building optimized production bundle...');
runCommand(
'next build',
'Production build'
);
// 5. Verify build output
const BUILD_OUTPUT_DIR = path.join(__dirname, '../.next');
if (fs.existsSync(BUILD_OUTPUT_DIR)) {
console.log(`\nโ
Build completed successfully in ${BUILD_OUTPUT_DIR}`);
if (!isCI) {
// Get build stats - Skip in CI environment
const buildSize = getFolderSize(BUILD_OUTPUT_DIR);
console.log(`๐ Build size: ${(buildSize / 1024 / 1024).toFixed(2)} MB`);
console.log('\n๐ Next steps:');
console.log('1. Run "npm run start" to test the optimized build');
console.log('2. Check for any performance issues');
console.log('3. Deploy to production');
}
} else {
console.error('โ Build output not found. Build may have failed.');
process.exit(1);
}
// Helper function to calculate folder size
function getFolderSize(folderPath) {
let totalSize = 0;
function readDir(dirPath) {
const items = fs.readdirSync(dirPath);
for (const item of items) {
const itemPath = path.join(dirPath, item);
const stats = fs.statSync(itemPath);
if (stats.isFile()) {
totalSize += stats.size;
} else if (stats.isDirectory()) {
readDir(itemPath);
}
}
}
readDir(folderPath);
return totalSize;
}