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

8.94% Statements 11/123
100% Branches 0/0
100% Functions 0/0
8.94% Lines 11/123

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 140 141 142 143 144 1451x 1x 1x                 1x 1x 1x 1x 1x 1x 1x                                                                                                                                                                                                                                                             1x
/**
 * Dev command - Starts development server with hot reload
 */
 
import { Command } from 'commander';
import ora from 'ora';
import picocolors from 'picocolors';
import { spawn } from 'child_process';
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
 
export const devCommand = new Command('dev')
  .description('Start development server with hot reload')
  .option('-p, --port <port>', 'port number', '3000')
  .option('-h, --host <host>', 'host address', 'localhost')
  .option('--open', 'open browser automatically')
  .option('--no-hmr', 'disable hot module replacement')
  .action(async (options) => {
    console.log(picocolors.cyan('🚀 Starting Coherent.js development server...'));
    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);
    }
 
    const spinner = ora('Starting development server...').start();
 
    try {
      let devProcess;
 
      // Check for existing dev script
      if (packageJson.scripts && packageJson.scripts.dev) {
        spinner.text = 'Running dev script...';
        
        devProcess = spawn('npm', ['run', 'dev'], {
          stdio: 'inherit',
          cwd: process.cwd(),
          env: {
            ...process.env,
            PORT: options.port,
            HOST: options.host
          }
        });
      } else {
        // Default dev server for Coherent.js projects
        spinner.text = 'Starting default dev server...';
 
        // Check for different dev servers
        if (existsSync('vite.config.js') || existsSync('vite.config.ts')) {
          devProcess = spawn('npx', ['vite', '--port', options.port, '--host', options.host], {
            stdio: 'inherit',
            cwd: process.cwd()
          });
        } else if (existsSync('webpack.config.js')) {
          devProcess = spawn('npx', ['webpack', 'serve', '--port', options.port, '--host', options.host], {
            stdio: 'inherit',
            cwd: process.cwd()
          });
        } else if (packageJson.type === 'module' || existsSync('src/index.js')) {
          // Use nodemon for Node.js projects
          devProcess = spawn('npx', ['nodemon', 'src/index.js'], {
            stdio: 'inherit',
            cwd: process.cwd(),
            env: {
              ...process.env,
              PORT: options.port,
              HOST: options.host
            }
          });
        } else {
          throw new Error('No development server configuration found');
        }
      }
 
      spinner.stop();
 
      console.log(picocolors.green('✅ Development server started!'));
      console.log();
      console.log(picocolors.cyan('🌐 Local:'), `http://${options.host}:${options.port}`);
      
      if (options.host !== 'localhost') {
        console.log(picocolors.cyan('🔗 Network:'), `http://${options.host}:${options.port}`);
      }
      
      console.log();
      console.log(picocolors.gray('Press Ctrl+C to stop the server'));
      console.log();
 
      // Open browser if requested
      if (options.open) {
        const { default: open } = await import('open');
        await open(`http://${options.host}:${options.port}`);
      }
 
      // Handle process termination
      const cleanup = () => {
        console.log();
        console.log(picocolors.yellow('👋 Stopping development server...'));
        if (devProcess) {
          devProcess.kill();
        }
        process.exit(0);
      };
 
      process.on('SIGINT', cleanup);
      process.on('SIGTERM', cleanup);
 
      // Wait for the process to exit
      devProcess.on('exit', (code) => {
        if (code !== 0) {
          console.error(picocolors.red(`❌ Development server exited with code ${code}`));
          process.exit(code);
        }
      });
 
      devProcess.on('error', (error) => {
        console.error(picocolors.red('❌ Failed to start development server:'), error.message);
        process.exit(1);
      });
 
    } catch (error) {
      spinner.fail('Failed to start development server');
      console.error(picocolors.red('❌ Error:'), error.message);
      
      // Show helpful suggestions
      console.log();
      console.log(picocolors.yellow('💡 Suggestions:'));
      console.log(picocolors.gray('  • Make sure you have a dev script in package.json'));
      console.log(picocolors.gray('  • Install development dependencies: npm install'));
      console.log(picocolors.gray('  • Check if port', options.port, 'is available'));
      
      process.exit(1);
    }
  });