UNPKG

@ordojs/cli

Version:

Command-line interface for OrdoJS framework

152 lines 5.78 kB
/** * @fileoverview OrdoJS CLI - Dev command */ import { Command } from 'commander'; import readline from 'readline'; import { OrdoJSDevServer } from '../dev-server/server.js'; import { logger } from '../utils/index.js'; /** * Register the dev command */ export function registerDevCommand(program) { program .command('dev') .description('Start development server') .argument('[dir]', 'Directory to serve', '.') .option('-p, --port <port>', 'Port to listen on', '3000') .option('-h, --host <host>', 'Host to listen on', 'localhost') .option('--hmr', 'Enable hot module replacement', true) .option('--no-hmr', 'Disable hot module replacement') .action(async (dir, options) => { try { await devCommand(dir, options); } catch (error) { logger.error(`Dev server failed: ${error instanceof Error ? error.message : String(error)}`); process.exit(1); } }); } /** * Set up keyboard shortcuts for the dev server * * @param server - The development server instance */ function setupKeyboardShortcuts(server) { if (process.stdin.isTTY) { // Put stdin in raw mode to capture keystrokes readline.emitKeypressEvents(process.stdin); process.stdin.setRawMode(true); // Track restart state to prevent multiple restarts let isRestarting = false; process.stdin.on('keypress', async (str, key) => { // Ctrl+C - Exit the process if (key.ctrl && key.name === 'c') { logger.info('Shutting down...'); await server.stop(); process.exit(0); } // Shift+R - Restart the server with state preservation if (key.shift && key.name === 'r') { // Prevent multiple restarts from being triggered simultaneously if (isRestarting) { logger.warn('Restart already in progress, please wait...'); return; } isRestarting = true; logger.info('Restart requested (Shift+R)'); try { // Display progress indicator const startTime = Date.now(); const progressIndicator = startProgressIndicator('Restarting server'); // Preserve server state before restart const serverState = server.getServerState(); // Perform the restart await server.restart(); // Stop progress indicator stopProgressIndicator(progressIndicator); const duration = ((Date.now() - startTime) / 1000).toFixed(2); logger.success(`Server restarted successfully in ${duration}s`); // Log state preservation info if applicable if (Object.keys(serverState).length > 0) { logger.info('Server state was preserved during restart'); } } catch (error) { logger.error(`Failed to restart server: ${error instanceof Error ? error.message : String(error)}`); logger.info('Try stopping and starting the server manually if issues persist'); } finally { isRestarting = false; } } // ? - Show help if (key.name === '?') { logger.info('Keyboard shortcuts:'); logger.info(' Ctrl+C - Stop server and exit'); logger.info(' Shift+R - Restart server (preserves state)'); logger.info(' ? - Show this help'); } }); } } /** * Start a progress indicator in the console * * @param message - The message to display * @returns The interval ID for the progress indicator */ function startProgressIndicator(message) { const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; let i = 0; process.stdout.write('\n'); return setInterval(() => { const frame = frames[i = ++i % frames.length]; process.stdout.write(`\r${frame} ${message}...`); }, 80); } /** * Stop a progress indicator * * @param intervalId - The interval ID returned by startProgressIndicator */ function stopProgressIndicator(intervalId) { clearInterval(intervalId); process.stdout.write('\r \r'); } /** * Dev command implementation */ export async function devCommand(dir, options) { logger.info(`Starting development server...`); logger.info(`Directory: ${dir}`); logger.info(`Server: http://${options.host}:${options.port}`); logger.info(`HMR: ${options.hmr ? 'enabled' : 'disabled'}`); // Create and start the development server const server = new OrdoJSDevServer({ dir, host: options.host, port: options.port, hmr: options.hmr }); try { // Start the server await server.start(); // Set up keyboard shortcuts setupKeyboardShortcuts(server); logger.info('Press ? for available commands'); // Keep the process running until explicitly terminated await new Promise(() => { }); } catch (error) { // Ensure we stop the server if it failed to start properly try { await server.stop(); } catch (stopError) { logger.debug(`Error stopping server after failed start: ${stopError instanceof Error ? stopError.message : String(stopError)}`); } throw error; } } //# sourceMappingURL=dev.js.map