UNPKG

neex

Version:

Neex - Modern Fullstack Framework Built on Express and Next.js. Fast to Start, Easy to Build, Ready to Deploy

235 lines (234 loc) 8.96 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DevRunner = void 0; // src/dev-runner.ts - Development runner with file watching (nodemon functionality) const watcher_1 = require("./watcher"); const runner_1 = require("./runner"); const chalk_1 = __importDefault(require("chalk")); const figures_1 = __importDefault(require("figures")); const logger_process_1 = require("./logger-process"); class DevRunner { constructor(options) { this.commands = []; this.isRunning = false; this.restartCount = 0; this.startTime = new Date(); const defaultOptions = { parallel: false, printOutput: true, color: true, showTiming: true, prefix: true, stopOnError: false, minimalOutput: false, groupOutput: false, isServerMode: false, restartOnChange: true, clearConsole: false, signal: 'SIGTERM', watch: ['./'], ignore: [ 'node_modules/**', '.git/**', '*.log', 'dist/**', 'build/**', 'coverage/**', '.nyc_output/**', '*.tmp', '*.temp' ], ext: ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'], delay: 1000, verbose: false, showInfo: false, runnerName: 'neex dev', }; this.options = { ...defaultOptions, ...options }; } setupFileWatcher() { const watchOptions = { watch: this.options.watch || ['./'], ignore: this.options.ignore, ext: this.options.ext, delay: this.options.delay, verbose: this.options.verbose && this.options.showInfo // Only show verbose watcher logs if both verbose and showInfo are true }; this.fileWatcher = new watcher_1.FileWatcher(watchOptions); this.fileWatcher.on('change', (event) => { if (this.options.restartOnChange && this.isRunning) { this.handleFileChange(event); } }); } async handleFileChange(event) { const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`); if (this.options.showInfo) { logger_process_1.logger.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info'); } if (this.options.clearConsole) { console.clear(); } await this.restart(); } async runCommands() { if (this.commands.length === 0) { return []; } // Create a modified options object for the runner to clean up output const runnerOptions = { ...this.options, // Override prefix behavior to show clean command name customPrefix: (command) => { // Extract just the filename from the command const match = command.match(/(?:npx ts-node|node)\s+(.+)/); if (match) { const filePath = match[1]; const fileName = filePath.split('/').pop() || filePath; return `${fileName}`; } return command; } }; this.runner = new runner_1.Runner(runnerOptions); try { const results = await this.runner.run(this.commands); return results; } catch (error) { if (this.options.showInfo) { logger_process_1.logger.printLine(`Execution failed: ${error.message}`, 'error'); } return []; } } printDevBanner() { var _a, _b; if (!this.options.showInfo) { return; // Don't show banner if showInfo is false } const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`); const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000); const uptimeStr = this.formatUptime(uptime); console.log('\n' + chalk_1.default.bgGreen.black(` ${(_a = this.options.runnerName) === null || _a === void 0 ? void 0 : _a.toUpperCase()} MODE `) + '\n'); if (this.restartCount > 0) { console.log(`${prefix} ${chalk_1.default.green(`${figures_1.default.arrowUp} Restarted ${this.restartCount} times`)}`); } console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`)}`); console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Watching: ${((_b = this.options.watch) === null || _b === void 0 ? void 0 : _b.join(', ')) || 'current directory'}`)}`); if (this.options.ext && this.options.ext.length > 0) { console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Extensions: ${this.options.ext.join(', ')}`)}`); } console.log(''); } formatUptime(seconds) { if (seconds < 60) { return `${seconds}s`; } else if (seconds < 3600) { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}m ${remainingSeconds}s`; } else { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); return `${hours}h ${minutes}m`; } } async start(commands) { this.commands = commands; this.isRunning = true; this.startTime = new Date(); // Setup file watcher this.setupFileWatcher(); // Print development banner only if showInfo is true this.printDevBanner(); // Start file watcher if (this.fileWatcher) { await this.fileWatcher.start(); } // Run initial commands const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`); if (this.options.showInfo) { logger_process_1.logger.printLine(`${prefix} Starting development server...`, 'info'); } await this.runCommands(); // Set up graceful shutdown this.setupGracefulShutdown(); if (this.options.showInfo) { logger_process_1.logger.printLine(`${prefix} Development server started. Watching for changes...`, 'info'); logger_process_1.logger.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info'); } } async restart() { const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`); if (!this.isRunning) { return; } if (this.options.showInfo) { logger_process_1.logger.printLine(`${prefix} Restarting due to file changes...`, 'info'); } this.restartCount++; // Stop current processes if (this.runner) { this.runner.cleanup(this.options.signal); } // Wait a moment before restarting await new Promise(resolve => setTimeout(resolve, 500)); // Print restart banner only if showInfo is true this.printDevBanner(); // Run commands again await this.runCommands(); if (this.options.showInfo) { logger_process_1.logger.printLine(`${prefix} Restart completed. Watching for changes...`, 'info'); } } async stop() { const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`); if (!this.isRunning) { return; } this.isRunning = false; // Stop file watcher if (this.fileWatcher) { this.fileWatcher.stop(); } // Stop current processes if (this.runner) { this.runner.cleanup(this.options.signal); } const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000); const uptimeStr = this.formatUptime(uptime); } setupGracefulShutdown() { const handleSignal = (signal) => { this.stop().then(() => { process.exit(0); }); }; process.on('SIGINT', () => handleSignal('SIGINT')); process.on('SIGTERM', () => handleSignal('SIGTERM')); process.on('SIGQUIT', () => handleSignal('SIGQUIT')); } isActive() { return this.isRunning; } getUptime() { return Math.floor((Date.now() - this.startTime.getTime()) / 1000); } getRestartCount() { return this.restartCount; } getWatchedFiles() { var _a; return ((_a = this.fileWatcher) === null || _a === void 0 ? void 0 : _a.getWatchedFiles()) || []; } } exports.DevRunner = DevRunner;