neex 0.6.87 → 0.6.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/commands/dev-commands.js +70 -125
- package/dist/src/dev-manager.js +272 -51
- package/package.json +1 -1
|
@@ -7,43 +7,56 @@ exports.addDevCommands = void 0;
|
|
|
7
7
|
const dev_manager_js_1 = require("../dev-manager.js");
|
|
8
8
|
const logger_manager_js_1 = require("../logger-manager.js");
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const figures_1 = __importDefault(require("figures"));
|
|
10
13
|
function addDevCommands(program) {
|
|
11
14
|
let devManager = null;
|
|
12
|
-
|
|
15
|
+
let isShuttingDown = false;
|
|
16
|
+
// Ultra-fast Express dev command optimized for speed
|
|
13
17
|
program
|
|
14
18
|
.command('dev [file]')
|
|
15
|
-
.description('Start
|
|
16
|
-
.option('-w, --watch <patterns>', 'Watch patterns (comma-separated)', 'src/**/*')
|
|
17
|
-
.option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git')
|
|
18
|
-
.option('-e, --ext <extensions>', 'File extensions to watch', 'ts,tsx,js,jsx')
|
|
19
|
-
.option('-d, --delay <ms>', '
|
|
20
|
-
.option('--
|
|
19
|
+
.description('Start TypeScript development server with hot reloading (default: src/index.ts)')
|
|
20
|
+
.option('-w, --watch <patterns>', 'Watch additional patterns (comma-separated)', 'src/**/*')
|
|
21
|
+
.option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git,coverage')
|
|
22
|
+
.option('-e, --ext <extensions>', 'File extensions to watch (comma-separated)', 'ts,tsx,js,jsx,json')
|
|
23
|
+
.option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt, 800)
|
|
24
|
+
.option('-c, --no-color', 'Disable colored output')
|
|
25
|
+
.option('-q, --quiet', 'Reduce output verbosity')
|
|
26
|
+
.option('-v, --verbose', 'Verbose output')
|
|
21
27
|
.option('--no-clear', 'Don\'t clear console on restart')
|
|
22
|
-
.option('--no-color', 'Disable colored output')
|
|
23
|
-
.option('-q, --quiet', 'Minimal output')
|
|
24
|
-
.option('-v, --verbose', 'Verbose logging')
|
|
25
28
|
.option('--inspect', 'Enable Node.js inspector')
|
|
26
|
-
.option('--inspect-brk', 'Enable Node.js inspector with
|
|
27
|
-
.option('--env <file>', '
|
|
28
|
-
.option('--exec <command>', '
|
|
29
|
-
.option('--tsconfig <path>', 'TypeScript
|
|
30
|
-
.option('--no-source-maps', 'Disable source
|
|
31
|
-
.option('--transpile-only', 'Skip type checking
|
|
32
|
-
.option('--node-args <args>', 'Node.js arguments (comma-separated)', '')
|
|
29
|
+
.option('--inspect-brk', 'Enable Node.js inspector with break')
|
|
30
|
+
.option('--env <file>', 'Load environment variables from file', '.env')
|
|
31
|
+
.option('--exec <command>', 'Command to execute instead of built-in TypeScript compilation')
|
|
32
|
+
.option('--tsconfig <path>', 'Path to TypeScript configuration file')
|
|
33
|
+
.option('--no-source-maps', 'Disable source maps')
|
|
34
|
+
.option('--transpile-only', 'Skip type checking for faster compilation')
|
|
35
|
+
.option('--node-args <args>', 'Additional Node.js arguments (comma-separated)', '')
|
|
36
|
+
.option('--port <port>', 'Port to use if available', parseInt)
|
|
37
|
+
.option('--host <host>', 'Host to bind to')
|
|
38
|
+
.option('--hot-reload', 'Enable hot reloading for supported frameworks (e.g., Express)')
|
|
39
|
+
.option('--middleware', 'Inject middleware for features like hot reloading')
|
|
33
40
|
.action(async (file, options) => {
|
|
34
41
|
try {
|
|
35
42
|
const targetFile = file || 'src/index.ts';
|
|
36
|
-
const delay = options.fast ? 50 : options.delay;
|
|
37
43
|
if (!options.quiet) {
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting ${chalk_1.default.cyan('neex dev')} for ${chalk_1.default.cyan(targetFile)}`, 'info');
|
|
45
|
+
if (options.verbose) {
|
|
46
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
|
|
47
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Built-in TypeScript compilation`, 'info');
|
|
48
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reloading with intelligent caching`, 'info');
|
|
49
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
|
|
50
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Fast transpilation mode`, 'info');
|
|
51
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Dependency tracking`, 'info');
|
|
52
|
+
}
|
|
40
53
|
}
|
|
41
54
|
devManager = new dev_manager_js_1.DevManager({
|
|
42
55
|
file: targetFile,
|
|
43
56
|
watch: options.watch.split(',').map((p) => p.trim()),
|
|
44
57
|
ignore: options.ignore.split(',').map((p) => p.trim()),
|
|
45
58
|
extensions: options.ext.split(',').map((e) => e.trim()),
|
|
46
|
-
delay: delay,
|
|
59
|
+
delay: options.delay,
|
|
47
60
|
color: options.color,
|
|
48
61
|
quiet: options.quiet,
|
|
49
62
|
verbose: options.verbose,
|
|
@@ -55,125 +68,64 @@ function addDevCommands(program) {
|
|
|
55
68
|
tsConfig: options.tsconfig,
|
|
56
69
|
sourceMaps: options.sourceMaps,
|
|
57
70
|
transpileOnly: options.transpileOnly,
|
|
58
|
-
nodeArgs: options.nodeArgs ? options.nodeArgs.split(',').map((arg) => arg.trim()) : []
|
|
71
|
+
nodeArgs: options.nodeArgs ? options.nodeArgs.split(',').map((arg) => arg.trim()) : [],
|
|
72
|
+
port: options.port,
|
|
73
|
+
host: options.host,
|
|
74
|
+
hotReload: options.hotReload,
|
|
75
|
+
middleware: options.middleware
|
|
59
76
|
});
|
|
60
77
|
await devManager.start();
|
|
61
78
|
}
|
|
62
79
|
catch (error) {
|
|
63
80
|
if (error instanceof Error) {
|
|
64
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(
|
|
81
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Development server error: ${error.message}`, 'error');
|
|
65
82
|
}
|
|
66
83
|
else {
|
|
67
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(
|
|
84
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown development server error occurred`, 'error');
|
|
68
85
|
}
|
|
69
86
|
process.exit(1);
|
|
70
87
|
}
|
|
71
88
|
});
|
|
72
|
-
//
|
|
89
|
+
// Additional helper commands
|
|
73
90
|
program
|
|
74
91
|
.command('dev:clean')
|
|
75
|
-
.description('Clean development cache and
|
|
92
|
+
.description('Clean development server cache and temporary files')
|
|
76
93
|
.action(() => {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
let cleaned = false;
|
|
82
|
-
if (fs.existsSync(tempDir)) {
|
|
83
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
84
|
-
cleaned = true;
|
|
85
|
-
}
|
|
86
|
-
if (fs.existsSync(nodeModulesCache)) {
|
|
87
|
-
try {
|
|
88
|
-
fs.rmSync(nodeModulesCache, { recursive: true, force: true });
|
|
89
|
-
cleaned = true;
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
// Ignore cache cleanup errors
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (cleaned) {
|
|
96
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} Cache cleaned successfully`, 'info');
|
|
94
|
+
const tempDir = path_1.default.join(process.cwd(), '.neex');
|
|
95
|
+
if (fs_1.default.existsSync(tempDir)) {
|
|
96
|
+
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
|
|
97
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Cleaned development cache`, 'info');
|
|
97
98
|
}
|
|
98
99
|
else {
|
|
99
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.
|
|
100
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.info)} No cache to clean`, 'info');
|
|
100
101
|
}
|
|
101
102
|
});
|
|
102
|
-
// TypeScript config check
|
|
103
103
|
program
|
|
104
104
|
.command('dev:check')
|
|
105
|
-
.description('Check TypeScript configuration')
|
|
106
|
-
.option('--tsconfig <path>', 'TypeScript
|
|
105
|
+
.description('Check TypeScript configuration and dependencies')
|
|
106
|
+
.option('--tsconfig <path>', 'Path to TypeScript configuration file')
|
|
107
107
|
.action((options) => {
|
|
108
|
-
const path = require('path');
|
|
109
|
-
const fs = require('fs');
|
|
110
108
|
const configPath = options.tsconfig || 'tsconfig.json';
|
|
111
|
-
if (!
|
|
112
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(
|
|
109
|
+
if (!fs_1.default.existsSync(configPath)) {
|
|
110
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} TypeScript config not found: ${configPath}`, 'error');
|
|
113
111
|
process.exit(1);
|
|
114
112
|
}
|
|
115
113
|
try {
|
|
116
|
-
const config = JSON.parse(
|
|
117
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(
|
|
118
|
-
if (config.compilerOptions
|
|
119
|
-
|
|
120
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
121
|
-
logger_manager_js_1.loggerManager.printLine(`
|
|
122
|
-
logger_manager_js_1.loggerManager.printLine(`
|
|
123
|
-
logger_manager_js_1.loggerManager.printLine(`
|
|
124
|
-
logger_manager_js_1.loggerManager.printLine(` Source Maps: ${opts.sourceMap || false}`, 'info');
|
|
125
|
-
logger_manager_js_1.loggerManager.printLine(` Skip Lib Check: ${opts.skipLibCheck || false}`, 'info');
|
|
114
|
+
const config = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
|
|
115
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript config is valid`, 'info');
|
|
116
|
+
if (config.compilerOptions) {
|
|
117
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compiler Options:')}`, 'info');
|
|
118
|
+
logger_manager_js_1.loggerManager.printLine(` Target: ${config.compilerOptions.target || 'default'}`, 'info');
|
|
119
|
+
logger_manager_js_1.loggerManager.printLine(` Module: ${config.compilerOptions.module || 'default'}`, 'info');
|
|
120
|
+
logger_manager_js_1.loggerManager.printLine(` Strict: ${config.compilerOptions.strict || 'false'}`, 'info');
|
|
121
|
+
logger_manager_js_1.loggerManager.printLine(` Source Maps: ${config.compilerOptions.sourceMap || 'false'}`, 'info');
|
|
126
122
|
}
|
|
127
123
|
}
|
|
128
124
|
catch (error) {
|
|
129
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(
|
|
125
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Invalid TypeScript config: ${error.message}`, 'error');
|
|
130
126
|
process.exit(1);
|
|
131
127
|
}
|
|
132
128
|
});
|
|
133
|
-
// Performance info command
|
|
134
|
-
program
|
|
135
|
-
.command('dev:info')
|
|
136
|
-
.description('Show development server information')
|
|
137
|
-
.action(() => {
|
|
138
|
-
const path = require('path');
|
|
139
|
-
const fs = require('fs');
|
|
140
|
-
const os = require('os');
|
|
141
|
-
console.log('');
|
|
142
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('⚡')} ${chalk_1.default.bold('neex dev')} - Development Server Info`, 'info');
|
|
143
|
-
console.log('');
|
|
144
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('System:')}`, 'info');
|
|
145
|
-
logger_manager_js_1.loggerManager.printLine(` Platform: ${os.platform()} ${os.arch()}`, 'info');
|
|
146
|
-
logger_manager_js_1.loggerManager.printLine(` Node.js: ${process.version}`, 'info');
|
|
147
|
-
logger_manager_js_1.loggerManager.printLine(` Memory: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB used`, 'info');
|
|
148
|
-
console.log('');
|
|
149
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
|
|
150
|
-
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Ultra-fast TypeScript compilation`, 'info');
|
|
151
|
-
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Intelligent module caching`, 'info');
|
|
152
|
-
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reload with dependency tracking`, 'info');
|
|
153
|
-
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
|
|
154
|
-
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Memory-optimized processing`, 'info');
|
|
155
|
-
const tsConfigExists = fs.existsSync('tsconfig.json');
|
|
156
|
-
const packageJsonExists = fs.existsSync('package.json');
|
|
157
|
-
console.log('');
|
|
158
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Project:')}`, 'info');
|
|
159
|
-
logger_manager_js_1.loggerManager.printLine(` TypeScript Config: ${tsConfigExists ? chalk_1.default.green('✓') : chalk_1.default.red('✖')}`, 'info');
|
|
160
|
-
logger_manager_js_1.loggerManager.printLine(` Package.json: ${packageJsonExists ? chalk_1.default.green('✓') : chalk_1.default.red('✖')}`, 'info');
|
|
161
|
-
if (packageJsonExists) {
|
|
162
|
-
try {
|
|
163
|
-
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
164
|
-
if (pkg.name) {
|
|
165
|
-
logger_manager_js_1.loggerManager.printLine(` Name: ${pkg.name}`, 'info');
|
|
166
|
-
}
|
|
167
|
-
if (pkg.version) {
|
|
168
|
-
logger_manager_js_1.loggerManager.printLine(` Version: ${pkg.version}`, 'info');
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
// Ignore package.json parsing errors
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
console.log('');
|
|
176
|
-
});
|
|
177
129
|
// Cleanup function
|
|
178
130
|
const cleanupDev = () => {
|
|
179
131
|
if (devManager) {
|
|
@@ -181,27 +133,20 @@ function addDevCommands(program) {
|
|
|
181
133
|
devManager = null;
|
|
182
134
|
}
|
|
183
135
|
};
|
|
184
|
-
//
|
|
185
|
-
|
|
136
|
+
// Handle process termination
|
|
137
|
+
process.on('SIGINT', () => {
|
|
186
138
|
if (devManager) {
|
|
187
|
-
|
|
188
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Received ${signal}, shutting down...`, 'info');
|
|
139
|
+
logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGINT, shutting down gracefully...`, 'info');
|
|
189
140
|
cleanupDev();
|
|
190
141
|
process.exit(0);
|
|
191
142
|
}
|
|
192
|
-
};
|
|
193
|
-
process.on('SIGINT', () => handleSignal('SIGINT'));
|
|
194
|
-
process.on('SIGTERM', () => handleSignal('SIGTERM'));
|
|
195
|
-
// Handle uncaught exceptions
|
|
196
|
-
process.on('uncaughtException', (error) => {
|
|
197
|
-
console.error(chalk_1.default.red('Uncaught Exception:'), error);
|
|
198
|
-
cleanupDev();
|
|
199
|
-
process.exit(1);
|
|
200
143
|
});
|
|
201
|
-
process.on('
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
144
|
+
process.on('SIGTERM', () => {
|
|
145
|
+
if (devManager) {
|
|
146
|
+
logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGTERM, shutting down gracefully...`, 'info');
|
|
147
|
+
cleanupDev();
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
205
150
|
});
|
|
206
151
|
return { cleanupDev };
|
|
207
152
|
}
|
package/dist/src/dev-manager.js
CHANGED
|
@@ -27,7 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.DevManager = void 0;
|
|
30
|
-
// src/dev-manager.ts -
|
|
30
|
+
// src/dev-manager.ts - Development process manager for Node.js applications
|
|
31
31
|
const child_process_1 = require("child_process");
|
|
32
32
|
const chokidar_1 = require("chokidar");
|
|
33
33
|
const logger_manager_js_1 = require("./logger-manager.js");
|
|
@@ -37,6 +37,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
37
37
|
const lodash_1 = require("lodash");
|
|
38
38
|
const ts = __importStar(require("typescript"));
|
|
39
39
|
const crypto_1 = __importDefault(require("crypto"));
|
|
40
|
+
const net_1 = __importDefault(require("net"));
|
|
40
41
|
class DevManager {
|
|
41
42
|
constructor(options) {
|
|
42
43
|
this.process = null;
|
|
@@ -46,11 +47,23 @@ class DevManager {
|
|
|
46
47
|
this.startTime = null;
|
|
47
48
|
this.moduleCache = new Map();
|
|
48
49
|
this.currentTempFile = null;
|
|
50
|
+
this.serverInfo = null;
|
|
51
|
+
this.hotReloadClient = null;
|
|
52
|
+
this.isExpressApp = false;
|
|
53
|
+
this.lastCompileTime = 0;
|
|
54
|
+
this.performanceMetrics = {
|
|
55
|
+
averageRestartTime: 0,
|
|
56
|
+
totalRestarts: 0,
|
|
57
|
+
cacheHits: 0,
|
|
58
|
+
cacheMisses: 0
|
|
59
|
+
};
|
|
49
60
|
this.options = options;
|
|
50
|
-
this.tempDir = path_1.default.join(process.cwd(), '.neex
|
|
61
|
+
this.tempDir = path_1.default.join(process.cwd(), '.neex');
|
|
51
62
|
this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), Math.max(options.delay, 100));
|
|
52
63
|
this.tsCompilerOptions = this.loadTsConfig();
|
|
53
64
|
this.setupTempDir();
|
|
65
|
+
this.detectExpressApp();
|
|
66
|
+
this.setupHotReloadClient();
|
|
54
67
|
}
|
|
55
68
|
setupTempDir() {
|
|
56
69
|
if (fs_1.default.existsSync(this.tempDir)) {
|
|
@@ -62,6 +75,64 @@ class DevManager {
|
|
|
62
75
|
}
|
|
63
76
|
}
|
|
64
77
|
fs_1.default.mkdirSync(this.tempDir, { recursive: true });
|
|
78
|
+
// Create cache directory
|
|
79
|
+
const cacheDir = path_1.default.join(this.tempDir, 'cache');
|
|
80
|
+
fs_1.default.mkdirSync(cacheDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
detectExpressApp() {
|
|
83
|
+
try {
|
|
84
|
+
const fileContent = fs_1.default.readFileSync(this.options.file, 'utf8');
|
|
85
|
+
this.isExpressApp = /import.*express|require.*express|app\.listen|server\.listen/.test(fileContent);
|
|
86
|
+
if (this.options.verbose) {
|
|
87
|
+
logger_manager_js_1.loggerManager.printLine(`Detected ${this.isExpressApp ? 'Express' : 'Node.js'} application`, 'info');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
this.isExpressApp = false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
setupHotReloadClient() {
|
|
95
|
+
if (!this.options.hotReload || !this.isExpressApp)
|
|
96
|
+
return;
|
|
97
|
+
this.hotReloadClient = `
|
|
98
|
+
// Hot reload client for Express development
|
|
99
|
+
(function() {
|
|
100
|
+
if (typeof window === 'undefined') return;
|
|
101
|
+
|
|
102
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
103
|
+
const wsUrl = protocol + '//' + window.location.host + '/__neex_hot_reload';
|
|
104
|
+
|
|
105
|
+
function connect() {
|
|
106
|
+
const ws = new WebSocket(wsUrl);
|
|
107
|
+
|
|
108
|
+
ws.onopen = function() {
|
|
109
|
+
console.log('🔥 Hot reload connected');
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
ws.onmessage = function(event) {
|
|
113
|
+
const data = JSON.parse(event.data);
|
|
114
|
+
|
|
115
|
+
if (data.type === 'reload') {
|
|
116
|
+
console.log('🔄 Reloading page...');
|
|
117
|
+
window.location.reload();
|
|
118
|
+
} else if (data.type === 'error') {
|
|
119
|
+
console.error('🚨 Build error:', data.message);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
ws.onclose = function() {
|
|
124
|
+
console.log('🔌 Hot reload disconnected, retrying...');
|
|
125
|
+
setTimeout(connect, 1000);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
ws.onerror = function(error) {
|
|
129
|
+
console.error('❌ Hot reload error:', error);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
connect();
|
|
134
|
+
})();
|
|
135
|
+
`;
|
|
65
136
|
}
|
|
66
137
|
loadTsConfig() {
|
|
67
138
|
const configPath = this.options.tsConfig || 'tsconfig.json';
|
|
@@ -81,7 +152,9 @@ class DevManager {
|
|
|
81
152
|
inlineSources: false,
|
|
82
153
|
removeComments: false,
|
|
83
154
|
preserveConstEnums: false,
|
|
84
|
-
isolatedModules: true,
|
|
155
|
+
isolatedModules: true,
|
|
156
|
+
incremental: true,
|
|
157
|
+
tsBuildInfoFile: path_1.default.join(this.tempDir, 'tsconfig.tsbuildinfo'),
|
|
85
158
|
};
|
|
86
159
|
if (fs_1.default.existsSync(configPath)) {
|
|
87
160
|
try {
|
|
@@ -100,29 +173,44 @@ class DevManager {
|
|
|
100
173
|
return defaultOptions;
|
|
101
174
|
}
|
|
102
175
|
loadEnvFile() {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
176
|
+
const envFiles = [
|
|
177
|
+
this.options.envFile,
|
|
178
|
+
'.env.development',
|
|
179
|
+
'.env.local',
|
|
180
|
+
'.env'
|
|
181
|
+
].filter(Boolean);
|
|
182
|
+
for (const envFile of envFiles) {
|
|
183
|
+
if (fs_1.default.existsSync(envFile)) {
|
|
184
|
+
try {
|
|
185
|
+
const envContent = fs_1.default.readFileSync(envFile, 'utf8');
|
|
186
|
+
const lines = envContent.split('\n');
|
|
187
|
+
for (const line of lines) {
|
|
188
|
+
const trimmed = line.trim();
|
|
189
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
190
|
+
const [key, ...values] = trimmed.split('=');
|
|
191
|
+
if (key && values.length > 0) {
|
|
192
|
+
const value = values.join('=').trim().replace(/^["']|["']$/g, '');
|
|
193
|
+
if (!process.env[key.trim()]) {
|
|
194
|
+
process.env[key.trim()] = value;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
113
197
|
}
|
|
114
198
|
}
|
|
199
|
+
if (this.options.verbose) {
|
|
200
|
+
logger_manager_js_1.loggerManager.printLine(`Loaded environment from ${envFile}`, 'info');
|
|
201
|
+
}
|
|
202
|
+
break;
|
|
115
203
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
204
|
+
catch (error) {
|
|
205
|
+
if (this.options.verbose) {
|
|
206
|
+
logger_manager_js_1.loggerManager.printLine(`Failed to load ${envFile}: ${error.message}`, 'warn');
|
|
207
|
+
}
|
|
120
208
|
}
|
|
121
209
|
}
|
|
122
210
|
}
|
|
123
211
|
}
|
|
124
212
|
createHash(content) {
|
|
125
|
-
return crypto_1.default.createHash('
|
|
213
|
+
return crypto_1.default.createHash('sha256').update(content).digest('hex').substring(0, 16);
|
|
126
214
|
}
|
|
127
215
|
extractDependencies(sourceCode, filePath) {
|
|
128
216
|
const dependencies = [];
|
|
@@ -134,7 +222,7 @@ class DevManager {
|
|
|
134
222
|
let resolvedPath = path_1.default.resolve(path_1.default.dirname(filePath), importPath);
|
|
135
223
|
// Try to resolve with extensions
|
|
136
224
|
if (!fs_1.default.existsSync(resolvedPath)) {
|
|
137
|
-
for (const ext of
|
|
225
|
+
for (const ext of this.options.extensions.map(e => `.${e}`)) {
|
|
138
226
|
const withExt = resolvedPath + ext;
|
|
139
227
|
if (fs_1.default.existsSync(withExt)) {
|
|
140
228
|
resolvedPath = withExt;
|
|
@@ -144,7 +232,7 @@ class DevManager {
|
|
|
144
232
|
}
|
|
145
233
|
// Try index files
|
|
146
234
|
if (!fs_1.default.existsSync(resolvedPath)) {
|
|
147
|
-
for (const ext of
|
|
235
|
+
for (const ext of this.options.extensions.map(e => `.${e}`)) {
|
|
148
236
|
const indexPath = path_1.default.join(resolvedPath, 'index' + ext);
|
|
149
237
|
if (fs_1.default.existsSync(indexPath)) {
|
|
150
238
|
resolvedPath = indexPath;
|
|
@@ -159,67 +247,125 @@ class DevManager {
|
|
|
159
247
|
}
|
|
160
248
|
return dependencies;
|
|
161
249
|
}
|
|
250
|
+
extractExports(sourceCode) {
|
|
251
|
+
const exports = [];
|
|
252
|
+
const exportRegex = /export\s+(?:default\s+)?(?:class|function|const|let|var|interface|type|enum)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
|
|
253
|
+
let match;
|
|
254
|
+
while ((match = exportRegex.exec(sourceCode)) !== null) {
|
|
255
|
+
exports.push(match[1]);
|
|
256
|
+
}
|
|
257
|
+
return exports;
|
|
258
|
+
}
|
|
162
259
|
compileModule(filePath, forceRecompile = false) {
|
|
163
260
|
const absolutePath = path_1.default.resolve(filePath);
|
|
261
|
+
const compileStart = Date.now();
|
|
164
262
|
try {
|
|
165
263
|
const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
|
|
166
264
|
const hash = this.createHash(sourceCode);
|
|
167
265
|
const cached = this.moduleCache.get(absolutePath);
|
|
168
266
|
// Check if we can use cached version
|
|
169
267
|
if (!forceRecompile && cached && cached.hash === hash) {
|
|
268
|
+
this.performanceMetrics.cacheHits++;
|
|
170
269
|
return cached;
|
|
171
270
|
}
|
|
271
|
+
this.performanceMetrics.cacheMisses++;
|
|
172
272
|
const dependencies = this.extractDependencies(sourceCode, absolutePath);
|
|
273
|
+
const exports = this.extractExports(sourceCode);
|
|
173
274
|
// Fast transpile without type checking for development
|
|
174
275
|
const result = ts.transpileModule(sourceCode, {
|
|
175
276
|
compilerOptions: this.tsCompilerOptions,
|
|
176
277
|
fileName: absolutePath,
|
|
177
|
-
reportDiagnostics:
|
|
278
|
+
reportDiagnostics: this.options.verbose
|
|
178
279
|
});
|
|
179
280
|
const moduleInfo = {
|
|
180
281
|
code: result.outputText,
|
|
181
282
|
map: result.sourceMapText,
|
|
182
283
|
hash,
|
|
183
284
|
timestamp: Date.now(),
|
|
184
|
-
dependencies
|
|
285
|
+
dependencies,
|
|
286
|
+
exports
|
|
185
287
|
};
|
|
186
288
|
this.moduleCache.set(absolutePath, moduleInfo);
|
|
187
289
|
if (this.options.verbose) {
|
|
188
|
-
|
|
290
|
+
const compileTime = Date.now() - compileStart;
|
|
291
|
+
logger_manager_js_1.loggerManager.printLine(`Compiled ${path_1.default.relative(process.cwd(), filePath)} (${compileTime}ms)`, 'info');
|
|
189
292
|
}
|
|
190
293
|
return moduleInfo;
|
|
191
294
|
}
|
|
192
295
|
catch (error) {
|
|
193
|
-
logger_manager_js_1.loggerManager.printLine(`Compilation error: ${error.message}`, 'error');
|
|
296
|
+
logger_manager_js_1.loggerManager.printLine(`Compilation error in ${filePath}: ${error.message}`, 'error');
|
|
194
297
|
throw error;
|
|
195
298
|
}
|
|
196
299
|
}
|
|
197
300
|
invalidateModuleCache(filePath) {
|
|
198
301
|
const absolutePath = path_1.default.resolve(filePath);
|
|
302
|
+
const toRemove = new Set();
|
|
199
303
|
// Remove the file itself
|
|
200
|
-
|
|
201
|
-
// Remove any modules that depend on this file
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
304
|
+
toRemove.add(absolutePath);
|
|
305
|
+
// Remove any modules that depend on this file (recursive)
|
|
306
|
+
const findDependents = (targetPath) => {
|
|
307
|
+
for (const [cachedPath, info] of this.moduleCache.entries()) {
|
|
308
|
+
if (info.dependencies.includes(targetPath) && !toRemove.has(cachedPath)) {
|
|
309
|
+
toRemove.add(cachedPath);
|
|
310
|
+
findDependents(cachedPath);
|
|
311
|
+
}
|
|
206
312
|
}
|
|
207
|
-
}
|
|
313
|
+
};
|
|
314
|
+
findDependents(absolutePath);
|
|
315
|
+
// Remove all affected modules
|
|
208
316
|
for (const pathToRemove of toRemove) {
|
|
209
317
|
this.moduleCache.delete(pathToRemove);
|
|
210
318
|
}
|
|
211
|
-
if (this.options.verbose && toRemove.
|
|
212
|
-
logger_manager_js_1.loggerManager.printLine(`Invalidated ${toRemove.
|
|
319
|
+
if (this.options.verbose && toRemove.size > 1) {
|
|
320
|
+
logger_manager_js_1.loggerManager.printLine(`Invalidated ${toRemove.size} modules`, 'info');
|
|
213
321
|
}
|
|
214
322
|
}
|
|
323
|
+
async findFreePort(startPort = 3000) {
|
|
324
|
+
return new Promise((resolve, reject) => {
|
|
325
|
+
const server = net_1.default.createServer();
|
|
326
|
+
server.listen(startPort, () => {
|
|
327
|
+
const port = server.address().port;
|
|
328
|
+
server.close(() => resolve(port));
|
|
329
|
+
});
|
|
330
|
+
server.on('error', () => {
|
|
331
|
+
this.findFreePort(startPort + 1).then(resolve).catch(reject);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
}
|
|
215
335
|
createExecutableFile() {
|
|
336
|
+
const startCompile = Date.now();
|
|
216
337
|
// Always force recompile the main file
|
|
217
338
|
const mainModule = this.compileModule(this.options.file, true);
|
|
218
339
|
// Create a unique temp file
|
|
219
340
|
const timestamp = Date.now();
|
|
220
341
|
const random = Math.random().toString(36).substr(2, 9);
|
|
221
|
-
const tempFile = path_1.default.join(this.tempDir, `
|
|
342
|
+
const tempFile = path_1.default.join(this.tempDir, `server-${timestamp}-${random}.js`);
|
|
222
343
|
let code = mainModule.code;
|
|
344
|
+
// Add hot reload middleware for Express apps
|
|
345
|
+
if (this.isExpressApp && this.options.hotReload) {
|
|
346
|
+
const hotReloadMiddleware = `
|
|
347
|
+
// Hot reload middleware injected by neex
|
|
348
|
+
const originalListen = require('http').Server.prototype.listen;
|
|
349
|
+
require('http').Server.prototype.listen = function(...args) {
|
|
350
|
+
const server = originalListen.apply(this, args);
|
|
351
|
+
|
|
352
|
+
// Setup WebSocket for hot reload
|
|
353
|
+
const WebSocket = require('ws');
|
|
354
|
+
const wss = new WebSocket.Server({ server, path: '/__neex_hot_reload' });
|
|
355
|
+
|
|
356
|
+
global.__neex_hot_reload = (type, data) => {
|
|
357
|
+
wss.clients.forEach(client => {
|
|
358
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
359
|
+
client.send(JSON.stringify({ type, ...data }));
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
return server;
|
|
365
|
+
};
|
|
366
|
+
`;
|
|
367
|
+
code = hotReloadMiddleware + '\n' + code;
|
|
368
|
+
}
|
|
223
369
|
// Add source map support
|
|
224
370
|
if (mainModule.map && this.options.sourceMaps) {
|
|
225
371
|
const mapFile = tempFile + '.map';
|
|
@@ -241,6 +387,7 @@ class DevManager {
|
|
|
241
387
|
}
|
|
242
388
|
}
|
|
243
389
|
this.currentTempFile = tempFile;
|
|
390
|
+
this.lastCompileTime = Date.now() - startCompile;
|
|
244
391
|
return tempFile;
|
|
245
392
|
}
|
|
246
393
|
async getExecuteCommand() {
|
|
@@ -257,50 +404,93 @@ class DevManager {
|
|
|
257
404
|
args.unshift('--inspect-brk');
|
|
258
405
|
if (this.options.sourceMaps)
|
|
259
406
|
args.unshift('--enable-source-maps');
|
|
407
|
+
// Memory optimization
|
|
408
|
+
args.unshift('--max-old-space-size=4096');
|
|
409
|
+
args.unshift('--optimize-for-size');
|
|
260
410
|
return { command: 'node', args };
|
|
261
411
|
}
|
|
262
412
|
clearConsole() {
|
|
263
413
|
if (this.options.clearConsole && process.stdout.isTTY) {
|
|
264
|
-
process.stdout.write('\x1Bc');
|
|
414
|
+
process.stdout.write('\x1Bc');
|
|
265
415
|
}
|
|
266
416
|
}
|
|
267
417
|
async startProcess() {
|
|
268
418
|
var _a, _b;
|
|
269
419
|
if (this.process)
|
|
270
420
|
return;
|
|
421
|
+
const restartStart = Date.now();
|
|
271
422
|
this.loadEnvFile();
|
|
272
423
|
try {
|
|
273
424
|
const { command, args } = await this.getExecuteCommand();
|
|
425
|
+
// Find free port for Express apps
|
|
426
|
+
if (this.isExpressApp && !process.env.PORT) {
|
|
427
|
+
const port = await this.findFreePort(this.options.port || 3000);
|
|
428
|
+
process.env.PORT = port.toString();
|
|
429
|
+
}
|
|
274
430
|
this.process = (0, child_process_1.spawn)(command, args, {
|
|
275
431
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
276
432
|
env: {
|
|
277
433
|
...process.env,
|
|
278
434
|
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
279
435
|
FORCE_COLOR: this.options.color ? '1' : '0',
|
|
280
|
-
|
|
436
|
+
NEEX_DEV_MODE: '1',
|
|
437
|
+
NEEX_HOT_RELOAD: this.options.hotReload ? '1' : '0',
|
|
281
438
|
},
|
|
282
|
-
detached: false
|
|
439
|
+
detached: false
|
|
283
440
|
});
|
|
284
441
|
this.startTime = new Date();
|
|
285
442
|
this.restartCount++;
|
|
443
|
+
// Update performance metrics
|
|
444
|
+
if (this.restartCount > 1) {
|
|
445
|
+
const restartTime = Date.now() - restartStart;
|
|
446
|
+
this.performanceMetrics.averageRestartTime =
|
|
447
|
+
(this.performanceMetrics.averageRestartTime * (this.restartCount - 2) + restartTime) / (this.restartCount - 1);
|
|
448
|
+
this.performanceMetrics.totalRestarts++;
|
|
449
|
+
}
|
|
286
450
|
if (!this.options.quiet) {
|
|
287
451
|
const timestamp = new Date().toLocaleTimeString();
|
|
288
452
|
const fileRelative = path_1.default.relative(process.cwd(), this.options.file);
|
|
453
|
+
const port = process.env.PORT ? `:${process.env.PORT}` : '';
|
|
454
|
+
const url = this.isExpressApp ? `http://localhost${port}` : '';
|
|
289
455
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('▶')} ${chalk_1.default.cyan(fileRelative)} ${chalk_1.default.dim(`#${this.restartCount} ${timestamp}`)}`, 'info');
|
|
456
|
+
if (url) {
|
|
457
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('🌐')} ${chalk_1.default.underline(url)}`, 'info');
|
|
458
|
+
}
|
|
459
|
+
if (this.options.verbose) {
|
|
460
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compile time:')} ${this.lastCompileTime}ms`, 'info');
|
|
461
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Cache hits:')} ${this.performanceMetrics.cacheHits}`, 'info');
|
|
462
|
+
}
|
|
290
463
|
}
|
|
291
|
-
|
|
464
|
+
this.serverInfo = {
|
|
465
|
+
port: parseInt(process.env.PORT || '3000'),
|
|
466
|
+
host: this.options.host || 'localhost',
|
|
467
|
+
pid: this.process.pid,
|
|
468
|
+
startTime: Date.now(),
|
|
469
|
+
restarts: this.restartCount
|
|
470
|
+
};
|
|
471
|
+
// Handle stdout/stderr with better formatting
|
|
292
472
|
(_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
293
|
-
|
|
473
|
+
const output = data.toString();
|
|
474
|
+
if (!this.options.quiet) {
|
|
475
|
+
process.stdout.write(output);
|
|
476
|
+
}
|
|
294
477
|
});
|
|
295
478
|
(_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
296
|
-
|
|
479
|
+
const output = data.toString();
|
|
480
|
+
if (!this.options.quiet) {
|
|
481
|
+
process.stderr.write(output);
|
|
482
|
+
}
|
|
297
483
|
});
|
|
298
484
|
this.process.on('error', (error) => {
|
|
299
485
|
logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
|
|
486
|
+
if (this.options.hotReload && global.__neex_hot_reload) {
|
|
487
|
+
global.__neex_hot_reload('error', { message: error.message });
|
|
488
|
+
}
|
|
300
489
|
});
|
|
301
490
|
this.process.on('exit', (code, signal) => {
|
|
302
491
|
if (this.process) {
|
|
303
492
|
this.process = null;
|
|
493
|
+
this.serverInfo = null;
|
|
304
494
|
if (!this.isRestarting && code !== 0) {
|
|
305
495
|
const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
|
|
306
496
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} Process exited with code ${code} (${duration}ms)`, 'error');
|
|
@@ -319,6 +509,7 @@ class DevManager {
|
|
|
319
509
|
return new Promise((resolve) => {
|
|
320
510
|
const proc = this.process;
|
|
321
511
|
this.process = null;
|
|
512
|
+
this.serverInfo = null;
|
|
322
513
|
const cleanup = () => {
|
|
323
514
|
resolve();
|
|
324
515
|
};
|
|
@@ -331,7 +522,8 @@ class DevManager {
|
|
|
331
522
|
if (!proc.killed) {
|
|
332
523
|
proc.kill('SIGKILL');
|
|
333
524
|
}
|
|
334
|
-
|
|
525
|
+
cleanup();
|
|
526
|
+
}, 2000);
|
|
335
527
|
}
|
|
336
528
|
catch (error) {
|
|
337
529
|
cleanup();
|
|
@@ -342,10 +534,14 @@ class DevManager {
|
|
|
342
534
|
if (this.isRestarting)
|
|
343
535
|
return;
|
|
344
536
|
this.isRestarting = true;
|
|
345
|
-
// Clear console
|
|
537
|
+
// Clear console for better UX
|
|
346
538
|
this.clearConsole();
|
|
347
539
|
if (!this.options.quiet) {
|
|
348
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⟳')} Restarting...`, 'info');
|
|
540
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⟳')} Restarting server...`, 'info');
|
|
541
|
+
}
|
|
542
|
+
// Notify hot reload clients
|
|
543
|
+
if (this.options.hotReload && global.__neex_hot_reload) {
|
|
544
|
+
global.__neex_hot_reload('reload', {});
|
|
349
545
|
}
|
|
350
546
|
// Stop current process
|
|
351
547
|
await this.stopProcess();
|
|
@@ -355,17 +551,21 @@ class DevManager {
|
|
|
355
551
|
}
|
|
356
552
|
setupWatcher() {
|
|
357
553
|
const watchPatterns = this.options.watch;
|
|
358
|
-
// Optimized ignore patterns
|
|
554
|
+
// Optimized ignore patterns for Express projects
|
|
359
555
|
const ignored = [
|
|
360
556
|
'node_modules/**',
|
|
361
557
|
'.git/**',
|
|
362
558
|
'dist/**',
|
|
363
559
|
'build/**',
|
|
364
|
-
'.neex
|
|
560
|
+
'.neex/**',
|
|
561
|
+
'coverage/**',
|
|
562
|
+
'logs/**',
|
|
365
563
|
'**/*.log',
|
|
366
564
|
'**/*.d.ts',
|
|
367
565
|
'**/*.map',
|
|
368
566
|
'**/*.tsbuildinfo',
|
|
567
|
+
'**/package-lock.json',
|
|
568
|
+
'**/yarn.lock',
|
|
369
569
|
...this.options.ignore
|
|
370
570
|
];
|
|
371
571
|
this.watcher = (0, chokidar_1.watch)(watchPatterns, {
|
|
@@ -373,10 +573,10 @@ class DevManager {
|
|
|
373
573
|
ignoreInitial: true,
|
|
374
574
|
followSymlinks: false,
|
|
375
575
|
usePolling: false,
|
|
376
|
-
atomic:
|
|
576
|
+
atomic: 100,
|
|
377
577
|
awaitWriteFinish: {
|
|
378
|
-
stabilityThreshold:
|
|
379
|
-
pollInterval:
|
|
578
|
+
stabilityThreshold: 150,
|
|
579
|
+
pollInterval: 100
|
|
380
580
|
}
|
|
381
581
|
});
|
|
382
582
|
this.watcher.on('change', (filePath) => {
|
|
@@ -408,24 +608,28 @@ class DevManager {
|
|
|
408
608
|
throw new Error(`Target file not found: ${this.options.file}`);
|
|
409
609
|
}
|
|
410
610
|
const ext = path_1.default.extname(this.options.file);
|
|
411
|
-
if (!
|
|
611
|
+
if (!this.options.extensions.map(e => `.${e}`).includes(ext)) {
|
|
412
612
|
throw new Error(`Unsupported file extension: ${ext}`);
|
|
413
613
|
}
|
|
414
614
|
// Clear any existing cache
|
|
415
615
|
this.moduleCache.clear();
|
|
416
616
|
this.setupTempDir();
|
|
417
617
|
if (!this.options.quiet) {
|
|
418
|
-
|
|
618
|
+
const appType = this.isExpressApp ? 'Express' : 'Node.js';
|
|
619
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('⚡')} Starting ${appType} development server...`, 'info');
|
|
419
620
|
}
|
|
420
621
|
this.setupWatcher();
|
|
421
622
|
await this.startProcess();
|
|
422
623
|
if (!this.options.quiet) {
|
|
423
624
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} Watching for changes...`, 'info');
|
|
625
|
+
if (this.options.hotReload) {
|
|
626
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('🔥')} Hot reload enabled`, 'info');
|
|
627
|
+
}
|
|
424
628
|
}
|
|
425
629
|
}
|
|
426
630
|
async stop() {
|
|
427
631
|
if (!this.options.quiet) {
|
|
428
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Stopping
|
|
632
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Stopping development server...`, 'info');
|
|
429
633
|
}
|
|
430
634
|
if (this.watcher) {
|
|
431
635
|
await this.watcher.close();
|
|
@@ -442,6 +646,23 @@ class DevManager {
|
|
|
442
646
|
}
|
|
443
647
|
}
|
|
444
648
|
this.moduleCache.clear();
|
|
649
|
+
if (this.options.verbose) {
|
|
650
|
+
logger_manager_js_1.loggerManager.printLine('Development server stopped', 'info');
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
getServerInfo() {
|
|
654
|
+
return this.serverInfo;
|
|
655
|
+
}
|
|
656
|
+
getPerformanceMetrics() {
|
|
657
|
+
return {
|
|
658
|
+
...this.performanceMetrics,
|
|
659
|
+
modulesCached: this.moduleCache.size,
|
|
660
|
+
lastCompileTime: this.lastCompileTime
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
async forceRestart() {
|
|
664
|
+
this.moduleCache.clear();
|
|
665
|
+
await this.restart();
|
|
445
666
|
}
|
|
446
667
|
}
|
|
447
668
|
exports.DevManager = DevManager;
|