neex 0.6.75 → 0.6.81
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 +88 -10
- package/dist/src/dev-manager.js +242 -68
- package/package.json +1 -1
|
@@ -7,16 +7,17 @@ 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 figures_1 = __importDefault(require("figures"));
|
|
10
11
|
function addDevCommands(program) {
|
|
11
12
|
let devManager = null;
|
|
12
|
-
//
|
|
13
|
+
// Enhanced dev command with built-in TypeScript compilation
|
|
13
14
|
program
|
|
14
15
|
.command('dev [file]')
|
|
15
|
-
.description('Start development server with hot reloading (default: src/index.ts)')
|
|
16
|
+
.description('Start TypeScript development server with hot reloading (default: src/index.ts)')
|
|
16
17
|
.option('-w, --watch <patterns>', 'Watch additional 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 (comma-separated)', 'ts,js,json')
|
|
19
|
-
.option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt,
|
|
18
|
+
.option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git,coverage')
|
|
19
|
+
.option('-e, --ext <extensions>', 'File extensions to watch (comma-separated)', 'ts,tsx,js,jsx,json')
|
|
20
|
+
.option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt, 800)
|
|
20
21
|
.option('-c, --no-color', 'Disable colored output')
|
|
21
22
|
.option('-q, --quiet', 'Reduce output verbosity')
|
|
22
23
|
.option('-v, --verbose', 'Verbose output')
|
|
@@ -24,11 +25,25 @@ function addDevCommands(program) {
|
|
|
24
25
|
.option('--inspect', 'Enable Node.js inspector')
|
|
25
26
|
.option('--inspect-brk', 'Enable Node.js inspector with break')
|
|
26
27
|
.option('--env <file>', 'Load environment variables from file', '.env')
|
|
27
|
-
.option('--exec <command>', 'Command to execute instead of
|
|
28
|
+
.option('--exec <command>', 'Command to execute instead of built-in TypeScript compilation')
|
|
29
|
+
.option('--tsconfig <path>', 'Path to TypeScript configuration file')
|
|
30
|
+
.option('--no-source-maps', 'Disable source maps')
|
|
31
|
+
.option('--transpile-only', 'Skip type checking for faster compilation')
|
|
32
|
+
.option('--node-args <args>', 'Additional Node.js arguments (comma-separated)', '')
|
|
28
33
|
.action(async (file, options) => {
|
|
29
34
|
try {
|
|
30
35
|
const targetFile = file || 'src/index.ts';
|
|
31
|
-
|
|
36
|
+
if (!options.quiet) {
|
|
37
|
+
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');
|
|
38
|
+
if (options.verbose) {
|
|
39
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
|
|
40
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Built-in TypeScript compilation`, 'info');
|
|
41
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reloading with intelligent caching`, 'info');
|
|
42
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
|
|
43
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Fast transpilation mode`, 'info');
|
|
44
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Dependency tracking`, 'info');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
32
47
|
devManager = new dev_manager_js_1.DevManager({
|
|
33
48
|
file: targetFile,
|
|
34
49
|
watch: options.watch.split(',').map((p) => p.trim()),
|
|
@@ -42,20 +57,68 @@ function addDevCommands(program) {
|
|
|
42
57
|
inspect: options.inspect,
|
|
43
58
|
inspectBrk: options.inspectBrk,
|
|
44
59
|
envFile: options.env,
|
|
45
|
-
execCommand: options.exec
|
|
60
|
+
execCommand: options.exec,
|
|
61
|
+
tsConfig: options.tsconfig,
|
|
62
|
+
sourceMaps: options.sourceMaps,
|
|
63
|
+
transpileOnly: options.transpileOnly,
|
|
64
|
+
nodeArgs: options.nodeArgs ? options.nodeArgs.split(',').map((arg) => arg.trim()) : []
|
|
46
65
|
});
|
|
47
66
|
await devManager.start();
|
|
48
67
|
}
|
|
49
68
|
catch (error) {
|
|
50
69
|
if (error instanceof Error) {
|
|
51
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
70
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Development server error: ${error.message}`, 'error');
|
|
52
71
|
}
|
|
53
72
|
else {
|
|
54
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
73
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown development server error occurred`, 'error');
|
|
55
74
|
}
|
|
56
75
|
process.exit(1);
|
|
57
76
|
}
|
|
58
77
|
});
|
|
78
|
+
// Additional helper commands
|
|
79
|
+
program
|
|
80
|
+
.command('dev:clean')
|
|
81
|
+
.description('Clean development server cache and temporary files')
|
|
82
|
+
.action(() => {
|
|
83
|
+
const path = require('path');
|
|
84
|
+
const fs = require('fs');
|
|
85
|
+
const tempDir = path.join(process.cwd(), '.neex-temp');
|
|
86
|
+
if (fs.existsSync(tempDir)) {
|
|
87
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
88
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Cleaned development cache`, 'info');
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.info)} No cache to clean`, 'info');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
program
|
|
95
|
+
.command('dev:check')
|
|
96
|
+
.description('Check TypeScript configuration and dependencies')
|
|
97
|
+
.option('--tsconfig <path>', 'Path to TypeScript configuration file')
|
|
98
|
+
.action((options) => {
|
|
99
|
+
const path = require('path');
|
|
100
|
+
const fs = require('fs');
|
|
101
|
+
const configPath = options.tsconfig || 'tsconfig.json';
|
|
102
|
+
if (!fs.existsSync(configPath)) {
|
|
103
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} TypeScript config not found: ${configPath}`, 'error');
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
108
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript config is valid`, 'info');
|
|
109
|
+
if (config.compilerOptions) {
|
|
110
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compiler Options:')}`, 'info');
|
|
111
|
+
logger_manager_js_1.loggerManager.printLine(` Target: ${config.compilerOptions.target || 'default'}`, 'info');
|
|
112
|
+
logger_manager_js_1.loggerManager.printLine(` Module: ${config.compilerOptions.module || 'default'}`, 'info');
|
|
113
|
+
logger_manager_js_1.loggerManager.printLine(` Strict: ${config.compilerOptions.strict || 'false'}`, 'info');
|
|
114
|
+
logger_manager_js_1.loggerManager.printLine(` Source Maps: ${config.compilerOptions.sourceMap || 'false'}`, 'info');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Invalid TypeScript config: ${error.message}`, 'error');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
59
122
|
// Cleanup function
|
|
60
123
|
const cleanupDev = () => {
|
|
61
124
|
if (devManager) {
|
|
@@ -63,6 +126,21 @@ function addDevCommands(program) {
|
|
|
63
126
|
devManager = null;
|
|
64
127
|
}
|
|
65
128
|
};
|
|
129
|
+
// Handle process termination
|
|
130
|
+
process.on('SIGINT', () => {
|
|
131
|
+
if (devManager) {
|
|
132
|
+
logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGINT, shutting down gracefully...`, 'info');
|
|
133
|
+
cleanupDev();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
process.on('SIGTERM', () => {
|
|
138
|
+
if (devManager) {
|
|
139
|
+
logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGTERM, shutting down gracefully...`, 'info');
|
|
140
|
+
cleanupDev();
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
66
144
|
return { cleanupDev };
|
|
67
145
|
}
|
|
68
146
|
exports.addDevCommands = addDevCommands;
|
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 - Enhanced TypeScript development server with built-in compilation
|
|
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");
|
|
@@ -36,19 +36,7 @@ const figures_1 = __importDefault(require("figures"));
|
|
|
36
36
|
const path_1 = __importDefault(require("path"));
|
|
37
37
|
const fs_1 = __importDefault(require("fs"));
|
|
38
38
|
const lodash_1 = require("lodash");
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
42
|
-
return new Promise((resolve) => {
|
|
43
|
-
exec(`command -v ${command}`, (error) => {
|
|
44
|
-
resolve(!error);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
catch (e) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
39
|
+
const ts = __importStar(require("typescript"));
|
|
52
40
|
class DevManager {
|
|
53
41
|
constructor(options) {
|
|
54
42
|
this.process = null;
|
|
@@ -56,50 +44,201 @@ class DevManager {
|
|
|
56
44
|
this.isRestarting = false;
|
|
57
45
|
this.restartCount = 0;
|
|
58
46
|
this.startTime = null;
|
|
47
|
+
this.moduleCache = new Map();
|
|
48
|
+
this.fileWatcher = new Map();
|
|
59
49
|
this.options = options;
|
|
60
50
|
this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), options.delay);
|
|
51
|
+
this.tsCompilerOptions = this.loadTsConfig();
|
|
52
|
+
}
|
|
53
|
+
loadTsConfig() {
|
|
54
|
+
const configPath = this.options.tsConfig || 'tsconfig.json';
|
|
55
|
+
const defaultOptions = {
|
|
56
|
+
target: ts.ScriptTarget.ES2022,
|
|
57
|
+
module: ts.ModuleKind.CommonJS,
|
|
58
|
+
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
59
|
+
allowJs: true,
|
|
60
|
+
outDir: undefined,
|
|
61
|
+
rootDir: undefined,
|
|
62
|
+
strict: false,
|
|
63
|
+
esModuleInterop: true,
|
|
64
|
+
skipLibCheck: true,
|
|
65
|
+
forceConsistentCasingInFileNames: true,
|
|
66
|
+
resolveJsonModule: true,
|
|
67
|
+
declaration: false,
|
|
68
|
+
sourceMap: this.options.sourceMaps,
|
|
69
|
+
inlineSourceMap: false,
|
|
70
|
+
inlineSources: false,
|
|
71
|
+
};
|
|
72
|
+
if (fs_1.default.existsSync(configPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
75
|
+
if (configFile.error) {
|
|
76
|
+
logger_manager_js_1.loggerManager.printLine(`Error reading tsconfig.json: ${configFile.error.messageText}`, 'warn');
|
|
77
|
+
return defaultOptions;
|
|
78
|
+
}
|
|
79
|
+
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path_1.default.dirname(configPath));
|
|
80
|
+
if (parsedConfig.errors.length > 0) {
|
|
81
|
+
logger_manager_js_1.loggerManager.printLine(`Error parsing tsconfig.json: ${parsedConfig.errors[0].messageText}`, 'warn');
|
|
82
|
+
return defaultOptions;
|
|
83
|
+
}
|
|
84
|
+
// Override some options for development
|
|
85
|
+
const options = { ...parsedConfig.options, ...defaultOptions };
|
|
86
|
+
if (this.options.verbose) {
|
|
87
|
+
logger_manager_js_1.loggerManager.printLine(`Loaded TypeScript config from ${configPath}`, 'info');
|
|
88
|
+
}
|
|
89
|
+
return options;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
logger_manager_js_1.loggerManager.printLine(`Failed to load tsconfig.json: ${error.message}`, 'warn');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return defaultOptions;
|
|
61
96
|
}
|
|
62
97
|
loadEnvFile() {
|
|
63
98
|
if (this.options.envFile && fs_1.default.existsSync(this.options.envFile)) {
|
|
64
99
|
try {
|
|
65
100
|
const envContent = fs_1.default.readFileSync(this.options.envFile, 'utf8');
|
|
66
101
|
const lines = envContent.split('\n');
|
|
102
|
+
let loadedCount = 0;
|
|
67
103
|
for (const line of lines) {
|
|
68
104
|
const trimmed = line.trim();
|
|
69
105
|
if (trimmed && !trimmed.startsWith('#')) {
|
|
70
106
|
const [key, ...values] = trimmed.split('=');
|
|
71
107
|
if (key && values.length > 0) {
|
|
72
|
-
process.env[key.trim()] = values.join('=').trim();
|
|
108
|
+
process.env[key.trim()] = values.join('=').trim().replace(/^["']|["']$/g, '');
|
|
109
|
+
loadedCount++;
|
|
73
110
|
}
|
|
74
111
|
}
|
|
75
112
|
}
|
|
76
|
-
if (this.options.
|
|
77
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
113
|
+
if (!this.options.quiet && loadedCount > 0) {
|
|
114
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim(figures_1.default.info)} Loaded ${loadedCount} env variable${loadedCount > 1 ? 's' : ''} from ${path_1.default.basename(this.options.envFile)}`, 'info');
|
|
115
|
+
}
|
|
116
|
+
else if (this.options.verbose) {
|
|
117
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim(figures_1.default.info)} No env variables found in ${this.options.envFile}`, 'info');
|
|
78
118
|
}
|
|
79
119
|
}
|
|
80
120
|
catch (error) {
|
|
81
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
121
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Failed to load ${this.options.envFile}: ${error.message}`, 'warn');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
compileTypeScript(filePath) {
|
|
126
|
+
const absolutePath = path_1.default.resolve(filePath);
|
|
127
|
+
// Check cache first
|
|
128
|
+
const cached = this.moduleCache.get(absolutePath);
|
|
129
|
+
if (cached && !this.options.transpileOnly) {
|
|
130
|
+
return cached;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
|
|
134
|
+
const dependencies = new Set();
|
|
135
|
+
// Extract import/require dependencies
|
|
136
|
+
const importRegex = /(?:import|require)\s*(?:\(.*?\)|.*?from\s+)['"`]([^'"`]+)['"`]/g;
|
|
137
|
+
let match;
|
|
138
|
+
while ((match = importRegex.exec(sourceCode)) !== null) {
|
|
139
|
+
if (!match[1].startsWith('.'))
|
|
140
|
+
continue;
|
|
141
|
+
const depPath = path_1.default.resolve(path_1.default.dirname(absolutePath), match[1]);
|
|
142
|
+
dependencies.add(depPath);
|
|
143
|
+
}
|
|
144
|
+
let result;
|
|
145
|
+
if (this.options.transpileOnly) {
|
|
146
|
+
// Fast transpile without type checking
|
|
147
|
+
result = ts.transpileModule(sourceCode, {
|
|
148
|
+
compilerOptions: this.tsCompilerOptions,
|
|
149
|
+
fileName: absolutePath,
|
|
150
|
+
reportDiagnostics: false
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Full compilation with type checking
|
|
155
|
+
const program = ts.createProgram([absolutePath], this.tsCompilerOptions);
|
|
156
|
+
const sourceFile = program.getSourceFile(absolutePath);
|
|
157
|
+
if (!sourceFile) {
|
|
158
|
+
throw new Error(`Could not load source file: ${absolutePath}`);
|
|
159
|
+
}
|
|
160
|
+
// Check for errors
|
|
161
|
+
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
|
|
162
|
+
if (diagnostics.length > 0) {
|
|
163
|
+
const errors = diagnostics.map(diagnostic => {
|
|
164
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
165
|
+
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
166
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
167
|
+
return `${path_1.default.relative(process.cwd(), diagnostic.file.fileName)}:${line + 1}:${character + 1} - ${message}`;
|
|
168
|
+
}
|
|
169
|
+
return message;
|
|
170
|
+
});
|
|
171
|
+
logger_manager_js_1.loggerManager.printLine(`TypeScript compilation errors:\n${errors.join('\n')}`, 'error');
|
|
172
|
+
if (!this.options.quiet) {
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
result = ts.transpileModule(sourceCode, {
|
|
177
|
+
compilerOptions: this.tsCompilerOptions,
|
|
178
|
+
fileName: absolutePath,
|
|
179
|
+
reportDiagnostics: true
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const compiled = {
|
|
183
|
+
code: result.outputText,
|
|
184
|
+
map: result.sourceMapText,
|
|
185
|
+
dependencies
|
|
186
|
+
};
|
|
187
|
+
this.moduleCache.set(absolutePath, compiled);
|
|
188
|
+
return compiled;
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
logger_manager_js_1.loggerManager.printLine(`Compilation error in ${filePath}: ${error.message}`, 'error');
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
createTempFile(compiled, originalPath) {
|
|
196
|
+
const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
|
|
197
|
+
if (!fs_1.default.existsSync(tempDir)) {
|
|
198
|
+
fs_1.default.mkdirSync(tempDir, { recursive: true });
|
|
199
|
+
}
|
|
200
|
+
const tempFile = path_1.default.join(tempDir, `${path_1.default.basename(originalPath, path_1.default.extname(originalPath))}-${Date.now()}.js`);
|
|
201
|
+
let code = compiled.code;
|
|
202
|
+
// Handle source maps
|
|
203
|
+
if (compiled.map && this.options.sourceMaps) {
|
|
204
|
+
const mapFile = tempFile + '.map';
|
|
205
|
+
fs_1.default.writeFileSync(mapFile, compiled.map);
|
|
206
|
+
code += `\n//# sourceMappingURL=${path_1.default.basename(mapFile)}`;
|
|
207
|
+
}
|
|
208
|
+
fs_1.default.writeFileSync(tempFile, code);
|
|
209
|
+
return tempFile;
|
|
210
|
+
}
|
|
211
|
+
cleanupTempFiles() {
|
|
212
|
+
const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
|
|
213
|
+
if (fs_1.default.existsSync(tempDir)) {
|
|
214
|
+
try {
|
|
215
|
+
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
// Ignore cleanup errors
|
|
82
219
|
}
|
|
83
220
|
}
|
|
84
221
|
}
|
|
85
222
|
async getExecuteCommand() {
|
|
86
223
|
if (this.options.execCommand) {
|
|
87
224
|
const parts = this.options.execCommand.split(' ');
|
|
88
|
-
return { command: parts[0], args: [...parts.slice(1)
|
|
89
|
-
}
|
|
90
|
-
// Default to tsx for TypeScript files
|
|
91
|
-
const tsxExists = await isCommandAvailable('tsx');
|
|
92
|
-
if (!tsxExists) {
|
|
93
|
-
throw new Error('`tsx` command not found. Please install `tsx`');
|
|
225
|
+
return { command: parts[0], args: [...parts.slice(1)] };
|
|
94
226
|
}
|
|
95
|
-
|
|
227
|
+
// Compile TypeScript file
|
|
228
|
+
const compiled = this.compileTypeScript(this.options.file);
|
|
229
|
+
const tempFile = this.createTempFile(compiled, this.options.file);
|
|
230
|
+
const args = [...this.options.nodeArgs, tempFile];
|
|
96
231
|
if (this.options.inspect) {
|
|
97
232
|
args.unshift('--inspect');
|
|
98
233
|
}
|
|
99
234
|
if (this.options.inspectBrk) {
|
|
100
235
|
args.unshift('--inspect-brk');
|
|
101
236
|
}
|
|
102
|
-
|
|
237
|
+
// Enable source map support
|
|
238
|
+
if (this.options.sourceMaps) {
|
|
239
|
+
args.unshift('--enable-source-maps');
|
|
240
|
+
}
|
|
241
|
+
return { command: 'node', args };
|
|
103
242
|
}
|
|
104
243
|
clearConsole() {
|
|
105
244
|
if (this.options.clearConsole && process.stdout.isTTY) {
|
|
@@ -112,50 +251,58 @@ class DevManager {
|
|
|
112
251
|
return;
|
|
113
252
|
}
|
|
114
253
|
this.loadEnvFile();
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.process = (0, child_process_1.spawn)(command, args, {
|
|
120
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
121
|
-
shell: false,
|
|
122
|
-
env: {
|
|
123
|
-
...process.env,
|
|
124
|
-
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
125
|
-
FORCE_COLOR: this.options.color ? '1' : '0'
|
|
126
|
-
},
|
|
127
|
-
detached: true
|
|
128
|
-
});
|
|
129
|
-
this.startTime = new Date();
|
|
130
|
-
this.restartCount++;
|
|
131
|
-
if (!this.options.quiet) {
|
|
132
|
-
const timestamp = new Date().toLocaleTimeString();
|
|
133
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Started ${chalk_1.default.cyan(this.options.file)} ${chalk_1.default.dim(`(${timestamp})`)}`, 'info');
|
|
134
|
-
}
|
|
135
|
-
(_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
136
|
-
if (!this.options.quiet) {
|
|
137
|
-
process.stdout.write(data);
|
|
254
|
+
try {
|
|
255
|
+
const { command, args } = await this.getExecuteCommand();
|
|
256
|
+
if (this.options.verbose) {
|
|
257
|
+
logger_manager_js_1.loggerManager.printLine(`Executing: ${command} ${args.join(' ')}`, 'info');
|
|
138
258
|
}
|
|
139
|
-
|
|
140
|
-
|
|
259
|
+
this.process = (0, child_process_1.spawn)(command, args, {
|
|
260
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
261
|
+
shell: false,
|
|
262
|
+
env: {
|
|
263
|
+
...process.env,
|
|
264
|
+
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
265
|
+
FORCE_COLOR: this.options.color ? '1' : '0',
|
|
266
|
+
TS_NODE_DEV: '1',
|
|
267
|
+
NEEX_DEV: '1'
|
|
268
|
+
},
|
|
269
|
+
detached: true
|
|
270
|
+
});
|
|
271
|
+
this.startTime = new Date();
|
|
272
|
+
this.restartCount++;
|
|
141
273
|
if (!this.options.quiet) {
|
|
142
|
-
|
|
274
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
275
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Started ${chalk_1.default.cyan(path_1.default.relative(process.cwd(), this.options.file))} ${chalk_1.default.dim(`(${timestamp})`)}`, 'info');
|
|
143
276
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
277
|
+
(_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
278
|
+
if (!this.options.quiet) {
|
|
279
|
+
process.stdout.write(data);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
(_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
283
|
+
if (!this.options.quiet) {
|
|
284
|
+
process.stderr.write(data);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
this.process.on('error', (error) => {
|
|
288
|
+
logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
|
|
289
|
+
});
|
|
290
|
+
this.process.on('exit', (code, signal) => {
|
|
291
|
+
if (this.process) {
|
|
292
|
+
this.process = null;
|
|
293
|
+
if (!this.isRestarting) {
|
|
294
|
+
if (code !== 0) {
|
|
295
|
+
const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
|
|
296
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Process exited with code ${code} after ${duration}ms`, 'error');
|
|
297
|
+
}
|
|
155
298
|
}
|
|
156
299
|
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
logger_manager_js_1.loggerManager.printLine(`Failed to start process: ${error.message}`, 'error');
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
159
306
|
}
|
|
160
307
|
async stopProcess() {
|
|
161
308
|
if (!this.process) {
|
|
@@ -172,6 +319,7 @@ class DevManager {
|
|
|
172
319
|
if (!this.options.quiet) {
|
|
173
320
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.square)} Stopped process`, 'info');
|
|
174
321
|
}
|
|
322
|
+
this.cleanupTempFiles();
|
|
175
323
|
resolve();
|
|
176
324
|
};
|
|
177
325
|
proc.on('exit', cleanup);
|
|
@@ -190,7 +338,7 @@ class DevManager {
|
|
|
190
338
|
// Ignore
|
|
191
339
|
}
|
|
192
340
|
}
|
|
193
|
-
},
|
|
341
|
+
}, 3000);
|
|
194
342
|
}
|
|
195
343
|
}
|
|
196
344
|
catch (error) {
|
|
@@ -199,6 +347,17 @@ class DevManager {
|
|
|
199
347
|
}
|
|
200
348
|
});
|
|
201
349
|
}
|
|
350
|
+
invalidateCache(filePath) {
|
|
351
|
+
const absolutePath = path_1.default.resolve(filePath);
|
|
352
|
+
// Remove from cache
|
|
353
|
+
this.moduleCache.delete(absolutePath);
|
|
354
|
+
// Remove dependent modules from cache
|
|
355
|
+
for (const [cachedPath, module] of this.moduleCache.entries()) {
|
|
356
|
+
if (module.dependencies.has(absolutePath)) {
|
|
357
|
+
this.moduleCache.delete(cachedPath);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
202
361
|
async restart() {
|
|
203
362
|
if (this.isRestarting) {
|
|
204
363
|
return;
|
|
@@ -210,7 +369,11 @@ class DevManager {
|
|
|
210
369
|
if (!this.options.quiet) {
|
|
211
370
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.arrowRight)} Restarting due to changes...`, 'info');
|
|
212
371
|
}
|
|
372
|
+
// Clear module cache
|
|
373
|
+
this.moduleCache.clear();
|
|
213
374
|
await this.stopProcess();
|
|
375
|
+
// Small delay to ensure cleanup
|
|
376
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
214
377
|
await this.startProcess();
|
|
215
378
|
this.isRestarting = false;
|
|
216
379
|
}
|
|
@@ -221,7 +384,9 @@ class DevManager {
|
|
|
221
384
|
'**/.git/**',
|
|
222
385
|
'**/dist/**',
|
|
223
386
|
'**/build/**',
|
|
387
|
+
'**/.neex-temp/**',
|
|
224
388
|
'**/*.log',
|
|
389
|
+
'**/*.d.ts',
|
|
225
390
|
...this.options.ignore.map(pattern => `**/${pattern}/**`)
|
|
226
391
|
];
|
|
227
392
|
this.watcher = (0, chokidar_1.watch)(watchPatterns, {
|
|
@@ -232,6 +397,7 @@ class DevManager {
|
|
|
232
397
|
atomic: 300
|
|
233
398
|
});
|
|
234
399
|
this.watcher.on('change', (filePath) => {
|
|
400
|
+
this.invalidateCache(filePath);
|
|
235
401
|
if (this.options.verbose) {
|
|
236
402
|
logger_manager_js_1.loggerManager.printLine(`File changed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
|
|
237
403
|
}
|
|
@@ -244,6 +410,7 @@ class DevManager {
|
|
|
244
410
|
this.debouncedRestart();
|
|
245
411
|
});
|
|
246
412
|
this.watcher.on('unlink', (filePath) => {
|
|
413
|
+
this.invalidateCache(filePath);
|
|
247
414
|
if (this.options.verbose) {
|
|
248
415
|
logger_manager_js_1.loggerManager.printLine(`File removed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
|
|
249
416
|
}
|
|
@@ -262,16 +429,23 @@ class DevManager {
|
|
|
262
429
|
if (!fs_1.default.existsSync(this.options.file)) {
|
|
263
430
|
throw new Error(`Target file not found: ${this.options.file}`);
|
|
264
431
|
}
|
|
265
|
-
|
|
432
|
+
// Validate TypeScript file
|
|
433
|
+
const ext = path_1.default.extname(this.options.file);
|
|
434
|
+
if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
|
|
435
|
+
throw new Error(`Unsupported file extension: ${ext}`);
|
|
436
|
+
}
|
|
437
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting TypeScript development server...`, 'info');
|
|
266
438
|
// Show configuration in verbose mode
|
|
267
439
|
if (this.options.verbose) {
|
|
268
440
|
logger_manager_js_1.loggerManager.printLine(`Target file: ${this.options.file}`, 'info');
|
|
269
441
|
logger_manager_js_1.loggerManager.printLine(`Watch patterns: ${this.options.watch.join(', ')}`, 'info');
|
|
270
442
|
logger_manager_js_1.loggerManager.printLine(`Restart delay: ${this.options.delay}ms`, 'info');
|
|
443
|
+
logger_manager_js_1.loggerManager.printLine(`Transpile only: ${this.options.transpileOnly}`, 'info');
|
|
444
|
+
logger_manager_js_1.loggerManager.printLine(`Source maps: ${this.options.sourceMaps}`, 'info');
|
|
271
445
|
}
|
|
272
446
|
this.setupWatcher();
|
|
273
447
|
await this.startProcess();
|
|
274
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)}
|
|
448
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript development server started. Watching for changes...`, 'info');
|
|
275
449
|
}
|
|
276
450
|
async stop() {
|
|
277
451
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Stopping development server...`, 'info');
|