@ordojs/cli
Version:
Command-line interface for OrdoJS framework
152 lines • 5.78 kB
JavaScript
/**
* @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