All files / packages/cli/src/commands build.js

9.09% Statements 11/121
100% Branches 0/0
100% Functions 0/0
9.09% Lines 11/121

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 1401x 1x 1x                 1x 1x 1x 1x 1x 1x 1x                                                                                                                                                                                                                                                   1x
/**
 * Build command - Builds the project for production
 */
 
import { Command } from 'commander';
import ora from 'ora';
import picocolors from 'picocolors';
import { execSync } from 'child_process';
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
 
export const buildCommand = new Command('build')
  .description('Build the project for production')
  .option('-w, --watch', 'watch for changes')
  .option('--analyze', 'analyze bundle size')
  .option('--no-minify', 'disable minification')
  .option('--no-optimize', 'disable optimizations')
  .action(async (options) => {
    console.log(picocolors.cyan('🏗️  Building Coherent.js project...'));
    console.log();
 
    // Check if we're in a Coherent.js project
    const packageJsonPath = join(process.cwd(), 'package.json');
    if (!existsSync(packageJsonPath)) {
      console.error(picocolors.red('❌ No package.json found. Are you in a project directory?'));
      process.exit(1);
    }
 
    let packageJson;
    try {
      packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
    } catch (error) {
      console.error(picocolors.red('❌ Failed to read package.json'));
      process.exit(1);
    }
 
    // Check for Coherent.js dependencies
    const hasCoherentDeps = packageJson.dependencies && 
      (packageJson.dependencies['@coherentjs/core'] || 
       packageJson.dependencies['coherentjs']);
 
    if (!hasCoherentDeps) {
      console.error(picocolors.red('❌ This doesn\'t appear to be a Coherent.js project'));
      console.error(picocolors.gray('   Missing @coherentjs/core dependency'));
      process.exit(1);
    }
 
    const spinner = ora('Building project...').start();
 
    try {
      // Check for existing build script
      if (packageJson.scripts && packageJson.scripts.build) {
        spinner.text = 'Running build script...';
        execSync('npm run build', { 
          stdio: options.watch ? 'inherit' : 'pipe',
          cwd: process.cwd()
        });
      } else {
        // Default build process for Coherent.js projects
        spinner.text = 'Building with default configuration...';
        
        // Check for different build tools
        if (existsSync('vite.config.js') || existsSync('vite.config.ts')) {
          execSync('npx vite build', { 
            stdio: options.watch ? 'inherit' : 'pipe',
            cwd: process.cwd()
          });
        } else if (existsSync('webpack.config.js')) {
          execSync('npx webpack --mode production', { 
            stdio: options.watch ? 'inherit' : 'pipe',
            cwd: process.cwd()
          });
        } else if (existsSync('rollup.config.js')) {
          execSync('npx rollup -c', { 
            stdio: options.watch ? 'inherit' : 'pipe',
            cwd: process.cwd()
          });
        } else {
          // Use esbuild as fallback
          spinner.text = 'Building with esbuild (fallback)...';
          execSync(`npx esbuild src/index.js --bundle --minify --outfile=dist/index.js --platform=node --format=esm`, {
            stdio: options.watch ? 'inherit' : 'pipe',
            cwd: process.cwd()
          });
        }
      }
 
      // Bundle analysis
      if (options.analyze) {
        spinner.text = 'Analyzing bundle...';
        
        try {
          // Try to run bundle analyzer if available
          execSync('npx webpack-bundle-analyzer dist/stats.json', { 
            stdio: 'inherit',
            cwd: process.cwd()
          });
        } catch (error) {
          console.log(picocolors.yellow('⚠️  Bundle analyzer not available'));
          console.log(picocolors.gray('   Install webpack-bundle-analyzer for detailed analysis'));
        }
      }
 
      spinner.succeed('Build completed successfully!');
 
      // Show build info
      console.log();
      console.log(picocolors.green('✅ Build completed!'));
      
      // Check if dist directory exists and show size info
      if (existsSync('dist')) {
        try {
          const distSize = execSync('du -sh dist', { encoding: 'utf-8' }).trim().split('\t')[0];
          console.log(picocolors.gray('📦 Output size:'), distSize);
        } catch (error) {
          // Ignore size calculation errors
        }
      }
 
      console.log();
      console.log(picocolors.cyan('Next steps:'));
      console.log(picocolors.gray('  Deploy your dist/ directory to your hosting provider'));
      console.log(picocolors.gray('  Or run: npm run start (if available)'));
      console.log();
 
    } catch (error) {
      spinner.fail('Build failed');
      console.error(picocolors.red('❌ Build error:'));
      console.error(error.message);
      
      // Show helpful error messages
      if (error.message.includes('command not found')) {
        console.log();
        console.log(picocolors.yellow('💡 Try installing dependencies:'));
        console.log(picocolors.gray('   npm install'));
      }
      
      process.exit(1);
    }
  });