slicejs-cli 3.6.2 → 3.6.4
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/LICENSE +21 -21
- package/README.md +226 -226
- package/client.js +744 -744
- package/commands/Print.js +163 -163
- package/commands/Validations.js +92 -92
- package/commands/build/build.js +40 -40
- package/commands/buildProduction/buildProduction.js +577 -579
- package/commands/bundle/bundle.js +234 -234
- package/commands/createComponent/VisualComponentTemplate.js +55 -55
- package/commands/createComponent/createComponent.js +128 -128
- package/commands/deleteComponent/deleteComponent.js +81 -81
- package/commands/doctor/doctor.js +440 -440
- package/commands/getComponent/getComponent.js +701 -692
- package/commands/init/init.js +467 -463
- package/commands/listComponents/listComponents.js +172 -172
- package/commands/startServer/startServer.js +261 -261
- package/commands/startServer/watchServer.js +66 -79
- package/commands/types/types.js +580 -580
- package/commands/utils/LocalCliDelegation.js +53 -53
- package/commands/utils/PackageManager.js +148 -148
- package/commands/utils/PathHelper.js +75 -75
- package/commands/utils/VersionChecker.js +169 -169
- package/commands/utils/bundling/BundleGenerator.js +2525 -2525
- package/commands/utils/bundling/DependencyAnalyzer.js +925 -925
- package/commands/utils/loadConfig.js +31 -31
- package/commands/utils/sliceScripts.js +23 -23
- package/commands/utils/updateManager.js +471 -471
- package/package.json +73 -73
- package/post.js +60 -60
|
@@ -1,261 +1,261 @@
|
|
|
1
|
-
// commands/startServer/startServer.js - IMPROVED WITH VALIDATION AND FEEDBACK
|
|
2
|
-
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { spawn } from 'child_process';
|
|
6
|
-
import { createServer } from 'net';
|
|
7
|
-
import setupWatcher, { stopWatcher } from './watchServer.js';
|
|
8
|
-
import Print from '../Print.js';
|
|
9
|
-
import { getConfigPath, getApiPath, getSrcPath, getDistPath, getPath } from '../utils/PathHelper.js';
|
|
10
|
-
import build from '../build/build.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Loads configuration from sliceConfig.json
|
|
14
|
-
*/
|
|
15
|
-
const loadConfig = () => {
|
|
16
|
-
try {
|
|
17
|
-
const configPath = getConfigPath(import.meta.url);
|
|
18
|
-
const rawData = fs.readFileSync(configPath, 'utf-8');
|
|
19
|
-
return JSON.parse(rawData);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
Print.error(`Loading configuration: ${error.message}`);
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Checks if a port is available
|
|
28
|
-
*/
|
|
29
|
-
async function isPortAvailable(port) {
|
|
30
|
-
return new Promise((resolve) => {
|
|
31
|
-
const server = createServer();
|
|
32
|
-
|
|
33
|
-
server.once('error', (err) => {
|
|
34
|
-
if (err.code === 'EADDRINUSE') {
|
|
35
|
-
resolve(false);
|
|
36
|
-
} else {
|
|
37
|
-
resolve(false);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
server.once('listening', () => {
|
|
42
|
-
server.close();
|
|
43
|
-
resolve(true);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
server.listen(port);
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Checks if a production build exists
|
|
52
|
-
*/
|
|
53
|
-
async function checkProductionBuild() {
|
|
54
|
-
const distDir = getDistPath(import.meta.url);
|
|
55
|
-
const bundleConfigPath = getPath(import.meta.url, 'dist', 'bundles', 'bundle.config.json');
|
|
56
|
-
return (await fs.pathExists(distDir)) && (await fs.pathExists(bundleConfigPath));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Checks if the development structure exists
|
|
61
|
-
*/
|
|
62
|
-
async function checkDevelopmentStructure() {
|
|
63
|
-
const srcDir = getSrcPath(import.meta.url);
|
|
64
|
-
const apiDir = getApiPath(import.meta.url);
|
|
65
|
-
|
|
66
|
-
return (await fs.pathExists(srcDir)) && (await fs.pathExists(apiDir));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Starts the Node.js server with arguments and improved feedback
|
|
71
|
-
*/
|
|
72
|
-
function startNodeServer(port, mode) {
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
const apiIndexPath = getApiPath(import.meta.url, 'index.js');
|
|
75
|
-
|
|
76
|
-
// Verify the file exists
|
|
77
|
-
if (!fs.existsSync(apiIndexPath)) {
|
|
78
|
-
reject(new Error(`Server file not found: ${apiIndexPath}`));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
Print.serverStatus('starting', 'Starting server...');
|
|
83
|
-
|
|
84
|
-
// Build arguments based on mode
|
|
85
|
-
const args = [apiIndexPath];
|
|
86
|
-
if (mode === 'production') {
|
|
87
|
-
args.push('--production');
|
|
88
|
-
} else {
|
|
89
|
-
args.push('--development');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Ensure the spawned server process receives NODE_ENV consistent with the
|
|
93
|
-
// requested mode. This guarantees code that only checks process.env.NODE_ENV
|
|
94
|
-
// (instead of CLI flags) will behave as expected.
|
|
95
|
-
const serverEnv = {
|
|
96
|
-
...process.env,
|
|
97
|
-
PORT: port,
|
|
98
|
-
NODE_ENV: mode === 'production' ? 'production' : (process.env.NODE_ENV || 'development')
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const serverProcess = spawn('node', args, {
|
|
102
|
-
stdio: ['inherit', 'pipe', 'pipe'],
|
|
103
|
-
env: serverEnv
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
let serverStarted = false;
|
|
107
|
-
let outputBuffer = '';
|
|
108
|
-
|
|
109
|
-
// Capture output to detect when the server is ready
|
|
110
|
-
serverProcess.stdout.on('data', (data) => {
|
|
111
|
-
const output = data.toString();
|
|
112
|
-
outputBuffer += output;
|
|
113
|
-
|
|
114
|
-
// Detect common messages indicating the server has started
|
|
115
|
-
if (!serverStarted && (
|
|
116
|
-
output.includes('Server running') ||
|
|
117
|
-
output.includes('listening on') ||
|
|
118
|
-
output.includes('Started on') ||
|
|
119
|
-
output.includes(`port ${port}`)
|
|
120
|
-
)) {
|
|
121
|
-
serverStarted = true;
|
|
122
|
-
Print.serverReady(port);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Display server output
|
|
126
|
-
process.stdout.write(output);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
serverProcess.stderr.on('data', (data) => {
|
|
130
|
-
const output = data.toString();
|
|
131
|
-
process.stderr.write(output);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
serverProcess.on('error', (error) => {
|
|
135
|
-
if (!serverStarted) {
|
|
136
|
-
Print.serverStatus('error', `Failed to start server: ${error.message}`);
|
|
137
|
-
reject(error);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
serverProcess.on('exit', (code, signal) => {
|
|
142
|
-
if (code !== null && code !== 0 && !serverStarted) {
|
|
143
|
-
reject(new Error(`Server exited with code ${code}`));
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// Manejar Ctrl+C
|
|
148
|
-
process.on('SIGINT', () => {
|
|
149
|
-
Print.newLine();
|
|
150
|
-
Print.info('Shutting down server...');
|
|
151
|
-
serverProcess.kill('SIGINT');
|
|
152
|
-
setTimeout(() => {
|
|
153
|
-
process.exit(0);
|
|
154
|
-
}, 100);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
process.on('SIGTERM', () => {
|
|
158
|
-
serverProcess.kill('SIGTERM');
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// If after 3 seconds we haven't detected startup, assume it's ready
|
|
162
|
-
setTimeout(() => {
|
|
163
|
-
if (!serverStarted) {
|
|
164
|
-
serverStarted = true;
|
|
165
|
-
Print.serverReady(port);
|
|
166
|
-
}
|
|
167
|
-
resolve(serverProcess);
|
|
168
|
-
}, 3000);
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Main function to start the server
|
|
174
|
-
*/
|
|
175
|
-
export default async function startServer(options = {}) {
|
|
176
|
-
const config = loadConfig();
|
|
177
|
-
const defaultPort = config?.server?.port || 3000;
|
|
178
|
-
|
|
179
|
-
const { mode = 'development', port = defaultPort, watch = false } = options;
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
Print.title(`🚀 Starting Slice.js ${mode} server...`);
|
|
183
|
-
Print.newLine();
|
|
184
|
-
|
|
185
|
-
// Verify project structure
|
|
186
|
-
if (!await checkDevelopmentStructure()) {
|
|
187
|
-
throw new Error('Project structure not found. Run "slice init" first.');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
let actualPort = await isPortAvailable(port) ? port : port + 1; // Try one more port
|
|
191
|
-
if(actualPort !== port) {
|
|
192
|
-
// Check if the fallback is available
|
|
193
|
-
const fallbackAvailable = await isPortAvailable(actualPort);
|
|
194
|
-
if(!fallbackAvailable) {
|
|
195
|
-
throw new Error(`Ports ${port} and ${actualPort} are in use.`);
|
|
196
|
-
}
|
|
197
|
-
Print.info(`ℹ️ Port ${port} in use, using ${actualPort} instead.`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
Print.serverStatus('checking', `Port ${actualPort} available ✓`);
|
|
201
|
-
Print.newLine();
|
|
202
|
-
|
|
203
|
-
if (mode === 'production') {
|
|
204
|
-
// Verify production build exists
|
|
205
|
-
if (!await checkProductionBuild()) {
|
|
206
|
-
Print.info('No production build found. Running "slice build"...');
|
|
207
|
-
const success = await build({});
|
|
208
|
-
if (!success) {
|
|
209
|
-
throw new Error('Build failed. Cannot start production server.');
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
Print.info('Production mode: serving optimized files from /dist');
|
|
213
|
-
} else {
|
|
214
|
-
Print.info('Development mode: serving files from /src (HMR enabled)');
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
Print.newLine();
|
|
218
|
-
|
|
219
|
-
// Start the server with arguments
|
|
220
|
-
let serverProcess = await startNodeServer(actualPort, mode);
|
|
221
|
-
|
|
222
|
-
// Configure watch mode if enabled
|
|
223
|
-
if (watch) {
|
|
224
|
-
Print.newLine();
|
|
225
|
-
const watcher = setupWatcher(serverProcess, async (changedPath) => {
|
|
226
|
-
if (serverProcess) {
|
|
227
|
-
serverProcess.kill();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Short delay to ensure port is freed
|
|
231
|
-
await new Promise(r => setTimeout(r, 500));
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
Print.info('🔄 File changed. Restarting server...');
|
|
235
|
-
|
|
236
|
-
serverProcess = await startNodeServer(actualPort, mode);
|
|
237
|
-
} catch (e) {
|
|
238
|
-
Print.error(`Failed to restart server: ${e.message}`);
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Cleanup en exit
|
|
243
|
-
const cleanup = () => {
|
|
244
|
-
stopWatcher(watcher);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
process.on('SIGINT', cleanup);
|
|
248
|
-
process.on('SIGTERM', cleanup);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
} catch (error) {
|
|
252
|
-
Print.newLine();
|
|
253
|
-
Print.error(`Failed to start development server: ${error.message}`);
|
|
254
|
-
throw error;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Exported utility functions
|
|
260
|
-
*/
|
|
261
|
-
export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
|
|
1
|
+
// commands/startServer/startServer.js - IMPROVED WITH VALIDATION AND FEEDBACK
|
|
2
|
+
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import { createServer } from 'net';
|
|
7
|
+
import setupWatcher, { stopWatcher } from './watchServer.js';
|
|
8
|
+
import Print from '../Print.js';
|
|
9
|
+
import { getConfigPath, getApiPath, getSrcPath, getDistPath, getPath } from '../utils/PathHelper.js';
|
|
10
|
+
import build from '../build/build.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Loads configuration from sliceConfig.json
|
|
14
|
+
*/
|
|
15
|
+
const loadConfig = () => {
|
|
16
|
+
try {
|
|
17
|
+
const configPath = getConfigPath(import.meta.url);
|
|
18
|
+
const rawData = fs.readFileSync(configPath, 'utf-8');
|
|
19
|
+
return JSON.parse(rawData);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
Print.error(`Loading configuration: ${error.message}`);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Checks if a port is available
|
|
28
|
+
*/
|
|
29
|
+
async function isPortAvailable(port) {
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
const server = createServer();
|
|
32
|
+
|
|
33
|
+
server.once('error', (err) => {
|
|
34
|
+
if (err.code === 'EADDRINUSE') {
|
|
35
|
+
resolve(false);
|
|
36
|
+
} else {
|
|
37
|
+
resolve(false);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
server.once('listening', () => {
|
|
42
|
+
server.close();
|
|
43
|
+
resolve(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
server.listen(port);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Checks if a production build exists
|
|
52
|
+
*/
|
|
53
|
+
async function checkProductionBuild() {
|
|
54
|
+
const distDir = getDistPath(import.meta.url);
|
|
55
|
+
const bundleConfigPath = getPath(import.meta.url, 'dist', 'bundles', 'bundle.config.json');
|
|
56
|
+
return (await fs.pathExists(distDir)) && (await fs.pathExists(bundleConfigPath));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Checks if the development structure exists
|
|
61
|
+
*/
|
|
62
|
+
async function checkDevelopmentStructure() {
|
|
63
|
+
const srcDir = getSrcPath(import.meta.url);
|
|
64
|
+
const apiDir = getApiPath(import.meta.url);
|
|
65
|
+
|
|
66
|
+
return (await fs.pathExists(srcDir)) && (await fs.pathExists(apiDir));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Starts the Node.js server with arguments and improved feedback
|
|
71
|
+
*/
|
|
72
|
+
function startNodeServer(port, mode) {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const apiIndexPath = getApiPath(import.meta.url, 'index.js');
|
|
75
|
+
|
|
76
|
+
// Verify the file exists
|
|
77
|
+
if (!fs.existsSync(apiIndexPath)) {
|
|
78
|
+
reject(new Error(`Server file not found: ${apiIndexPath}`));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Print.serverStatus('starting', 'Starting server...');
|
|
83
|
+
|
|
84
|
+
// Build arguments based on mode
|
|
85
|
+
const args = [apiIndexPath];
|
|
86
|
+
if (mode === 'production') {
|
|
87
|
+
args.push('--production');
|
|
88
|
+
} else {
|
|
89
|
+
args.push('--development');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Ensure the spawned server process receives NODE_ENV consistent with the
|
|
93
|
+
// requested mode. This guarantees code that only checks process.env.NODE_ENV
|
|
94
|
+
// (instead of CLI flags) will behave as expected.
|
|
95
|
+
const serverEnv = {
|
|
96
|
+
...process.env,
|
|
97
|
+
PORT: port,
|
|
98
|
+
NODE_ENV: mode === 'production' ? 'production' : (process.env.NODE_ENV || 'development')
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const serverProcess = spawn('node', args, {
|
|
102
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
103
|
+
env: serverEnv
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
let serverStarted = false;
|
|
107
|
+
let outputBuffer = '';
|
|
108
|
+
|
|
109
|
+
// Capture output to detect when the server is ready
|
|
110
|
+
serverProcess.stdout.on('data', (data) => {
|
|
111
|
+
const output = data.toString();
|
|
112
|
+
outputBuffer += output;
|
|
113
|
+
|
|
114
|
+
// Detect common messages indicating the server has started
|
|
115
|
+
if (!serverStarted && (
|
|
116
|
+
output.includes('Server running') ||
|
|
117
|
+
output.includes('listening on') ||
|
|
118
|
+
output.includes('Started on') ||
|
|
119
|
+
output.includes(`port ${port}`)
|
|
120
|
+
)) {
|
|
121
|
+
serverStarted = true;
|
|
122
|
+
Print.serverReady(port);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Display server output
|
|
126
|
+
process.stdout.write(output);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
serverProcess.stderr.on('data', (data) => {
|
|
130
|
+
const output = data.toString();
|
|
131
|
+
process.stderr.write(output);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
serverProcess.on('error', (error) => {
|
|
135
|
+
if (!serverStarted) {
|
|
136
|
+
Print.serverStatus('error', `Failed to start server: ${error.message}`);
|
|
137
|
+
reject(error);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
serverProcess.on('exit', (code, signal) => {
|
|
142
|
+
if (code !== null && code !== 0 && !serverStarted) {
|
|
143
|
+
reject(new Error(`Server exited with code ${code}`));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Manejar Ctrl+C
|
|
148
|
+
process.on('SIGINT', () => {
|
|
149
|
+
Print.newLine();
|
|
150
|
+
Print.info('Shutting down server...');
|
|
151
|
+
serverProcess.kill('SIGINT');
|
|
152
|
+
setTimeout(() => {
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}, 100);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
process.on('SIGTERM', () => {
|
|
158
|
+
serverProcess.kill('SIGTERM');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// If after 3 seconds we haven't detected startup, assume it's ready
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
if (!serverStarted) {
|
|
164
|
+
serverStarted = true;
|
|
165
|
+
Print.serverReady(port);
|
|
166
|
+
}
|
|
167
|
+
resolve(serverProcess);
|
|
168
|
+
}, 3000);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Main function to start the server
|
|
174
|
+
*/
|
|
175
|
+
export default async function startServer(options = {}) {
|
|
176
|
+
const config = loadConfig();
|
|
177
|
+
const defaultPort = config?.server?.port || 3000;
|
|
178
|
+
|
|
179
|
+
const { mode = 'development', port = defaultPort, watch = false } = options;
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
Print.title(`🚀 Starting Slice.js ${mode} server...`);
|
|
183
|
+
Print.newLine();
|
|
184
|
+
|
|
185
|
+
// Verify project structure
|
|
186
|
+
if (!await checkDevelopmentStructure()) {
|
|
187
|
+
throw new Error('Project structure not found. Run "slice init" first.');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let actualPort = await isPortAvailable(port) ? port : port + 1; // Try one more port
|
|
191
|
+
if(actualPort !== port) {
|
|
192
|
+
// Check if the fallback is available
|
|
193
|
+
const fallbackAvailable = await isPortAvailable(actualPort);
|
|
194
|
+
if(!fallbackAvailable) {
|
|
195
|
+
throw new Error(`Ports ${port} and ${actualPort} are in use.`);
|
|
196
|
+
}
|
|
197
|
+
Print.info(`ℹ️ Port ${port} in use, using ${actualPort} instead.`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
Print.serverStatus('checking', `Port ${actualPort} available ✓`);
|
|
201
|
+
Print.newLine();
|
|
202
|
+
|
|
203
|
+
if (mode === 'production') {
|
|
204
|
+
// Verify production build exists
|
|
205
|
+
if (!await checkProductionBuild()) {
|
|
206
|
+
Print.info('No production build found. Running "slice build"...');
|
|
207
|
+
const success = await build({});
|
|
208
|
+
if (!success) {
|
|
209
|
+
throw new Error('Build failed. Cannot start production server.');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
Print.info('Production mode: serving optimized files from /dist');
|
|
213
|
+
} else {
|
|
214
|
+
Print.info('Development mode: serving files from /src (HMR enabled)');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
Print.newLine();
|
|
218
|
+
|
|
219
|
+
// Start the server with arguments
|
|
220
|
+
let serverProcess = await startNodeServer(actualPort, mode);
|
|
221
|
+
|
|
222
|
+
// Configure watch mode if enabled
|
|
223
|
+
if (watch) {
|
|
224
|
+
Print.newLine();
|
|
225
|
+
const watcher = setupWatcher(serverProcess, async (changedPath) => {
|
|
226
|
+
if (serverProcess) {
|
|
227
|
+
serverProcess.kill();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Short delay to ensure port is freed
|
|
231
|
+
await new Promise(r => setTimeout(r, 500));
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
Print.info('🔄 File changed. Restarting server...');
|
|
235
|
+
|
|
236
|
+
serverProcess = await startNodeServer(actualPort, mode);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
Print.error(`Failed to restart server: ${e.message}`);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Cleanup en exit
|
|
243
|
+
const cleanup = () => {
|
|
244
|
+
stopWatcher(watcher);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
process.on('SIGINT', cleanup);
|
|
248
|
+
process.on('SIGTERM', cleanup);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
} catch (error) {
|
|
252
|
+
Print.newLine();
|
|
253
|
+
Print.error(`Failed to start development server: ${error.message}`);
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Exported utility functions
|
|
260
|
+
*/
|
|
261
|
+
export { checkProductionBuild, checkDevelopmentStructure, isPortAvailable };
|
|
@@ -1,79 +1,66 @@
|
|
|
1
|
-
import chokidar from 'chokidar';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import Print from '../Print.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Configures the watcher for project files
|
|
7
|
-
* @param {ChildProcess} serverProcess - Server process
|
|
8
|
-
* @returns {FSWatcher} - Chokidar watcher
|
|
9
|
-
*/
|
|
10
|
-
export default function setupWatcher(serverProcess, onRestart) {
|
|
11
|
-
Print.info('Watch mode enabled - monitoring file changes...');
|
|
12
|
-
Print.newLine();
|
|
13
|
-
|
|
14
|
-
const watcher = chokidar.watch(['
|
|
15
|
-
ignored: [
|
|
16
|
-
/(^|[\/\\])\../, // hidden files
|
|
17
|
-
'**/node_modules/**',
|
|
18
|
-
'**/dist/**',
|
|
19
|
-
'**/bundles/**',
|
|
20
|
-
'**/*.log'
|
|
21
|
-
],
|
|
22
|
-
persistent: true,
|
|
23
|
-
ignoreInitial: true,
|
|
24
|
-
awaitWriteFinish: {
|
|
25
|
-
stabilityThreshold: 100,
|
|
26
|
-
pollInterval: 50
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
let reloadTimeout;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.on('
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return watcher;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Stops the watcher safely
|
|
72
|
-
* @param {FSWatcher} watcher - Watcher to stop
|
|
73
|
-
*/
|
|
74
|
-
export function stopWatcher(watcher) {
|
|
75
|
-
if (watcher) {
|
|
76
|
-
watcher.close();
|
|
77
|
-
console.log(chalk.gray('Watch mode stopped'));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import Print from '../Print.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configures the watcher for project files
|
|
7
|
+
* @param {ChildProcess} serverProcess - Server process
|
|
8
|
+
* @returns {FSWatcher} - Chokidar watcher
|
|
9
|
+
*/
|
|
10
|
+
export default function setupWatcher(serverProcess, onRestart) {
|
|
11
|
+
Print.info('Watch mode enabled - monitoring file changes...');
|
|
12
|
+
Print.newLine();
|
|
13
|
+
|
|
14
|
+
const watcher = chokidar.watch(['api/**/*'], {
|
|
15
|
+
ignored: [
|
|
16
|
+
/(^|[\/\\])\../, // hidden files
|
|
17
|
+
'**/node_modules/**',
|
|
18
|
+
'**/dist/**',
|
|
19
|
+
'**/bundles/**',
|
|
20
|
+
'**/*.log'
|
|
21
|
+
],
|
|
22
|
+
persistent: true,
|
|
23
|
+
ignoreInitial: true,
|
|
24
|
+
awaitWriteFinish: {
|
|
25
|
+
stabilityThreshold: 100,
|
|
26
|
+
pollInterval: 50
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
let reloadTimeout;
|
|
31
|
+
|
|
32
|
+
const handleChange = (changedPath) => {
|
|
33
|
+
clearTimeout(reloadTimeout);
|
|
34
|
+
reloadTimeout = setTimeout(() => {
|
|
35
|
+
if (onRestart) {
|
|
36
|
+
console.log(chalk.yellow('🔄 API change detected, restarting server...'));
|
|
37
|
+
onRestart(changedPath);
|
|
38
|
+
}
|
|
39
|
+
}, 500);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
watcher
|
|
43
|
+
.on('change', handleChange)
|
|
44
|
+
.on('add', handleChange)
|
|
45
|
+
.on('unlink', handleChange)
|
|
46
|
+
.on('error', (error) => {
|
|
47
|
+
Print.error(`Watcher error: ${error.message}`);
|
|
48
|
+
})
|
|
49
|
+
.on('ready', () => {
|
|
50
|
+
console.log(chalk.gray('👀 Watching for file changes...'));
|
|
51
|
+
Print.newLine();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return watcher;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Stops the watcher safely
|
|
59
|
+
* @param {FSWatcher} watcher - Watcher to stop
|
|
60
|
+
*/
|
|
61
|
+
export function stopWatcher(watcher) {
|
|
62
|
+
if (watcher) {
|
|
63
|
+
watcher.close();
|
|
64
|
+
console.log(chalk.gray('Watch mode stopped'));
|
|
65
|
+
}
|
|
66
|
+
}
|