slicejs-cli 2.2.4 → 2.2.6

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.
@@ -1,233 +1,198 @@
1
- // commands/buildProduction/buildProduction.js
1
+ // commands/buildProduction/buildProduction.js - CON SLICECONFIG PORT
2
2
 
3
3
  import fs from 'fs-extra';
4
4
  import path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
- import { minify as terserMinify } from 'terser';
6
+ import UglifyJS from 'uglify-js';
7
+ import { minify } from 'html-minifier-terser';
7
8
  import CleanCSS from 'clean-css';
8
- import htmlMinifier from 'html-minifier-terser';
9
9
  import Print from '../Print.js';
10
10
 
11
11
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
12
 
13
13
  /**
14
- * Opciones de minificación para diferentes tipos de archivos
14
+ * Carga la configuración desde sliceConfig.json
15
15
  */
16
- const getMinificationOptions = () => ({
17
- js: {
18
- compress: {
19
- dead_code: true,
20
- drop_console: true, // Remover console.log en producción
21
- drop_debugger: true,
22
- pure_funcs: ['console.log', 'console.info', 'console.warn'],
23
- passes: 2
24
- },
25
- mangle: {
26
- toplevel: true,
27
- reserved: ['Slice', 'Controller', 'StylesManager'] // Preservar clases principales
28
- },
29
- output: {
30
- comments: false,
31
- beautify: false
32
- },
33
- toplevel: true
34
- },
35
- css: {
36
- level: 2, // Optimización agresiva
37
- returnPromise: false
38
- },
39
- html: {
40
- collapseWhitespace: true,
41
- removeComments: true,
42
- removeRedundantAttributes: true,
43
- removeEmptyAttributes: true,
44
- minifyCSS: true,
45
- minifyJS: true,
46
- useShortDoctype: true,
47
- removeAttributeQuotes: true,
48
- removeOptionalTags: true
16
+ const loadConfig = () => {
17
+ try {
18
+ const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
19
+ const rawData = fs.readFileSync(configPath, 'utf-8');
20
+ return JSON.parse(rawData);
21
+ } catch (error) {
22
+ Print.error(`Loading configuration: ${error.message}`);
23
+ return null;
49
24
  }
50
- });
25
+ };
51
26
 
52
27
  /**
53
- * Minifica un archivo JavaScript
28
+ * Verifica dependencias necesarias para el build
54
29
  */
55
- async function minifyJavaScript(content, filename) {
56
- try {
57
- const options = getMinificationOptions().js;
58
- const result = await terserMinify(content, options);
59
-
60
- if (result.error) {
61
- throw result.error;
62
- }
63
-
64
- const originalSize = Buffer.byteLength(content, 'utf8');
65
- const minifiedSize = Buffer.byteLength(result.code, 'utf8');
66
- const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
67
-
68
- Print.minificationResult(filename, originalSize, minifiedSize, savings);
69
-
70
- return result.code;
71
- } catch (error) {
72
- Print.error(`Error minifying ${filename}: ${error.message}`);
73
- throw error;
30
+ async function checkBuildDependencies() {
31
+ const srcDir = path.join(__dirname, '../../../../src');
32
+
33
+ if (!await fs.pathExists(srcDir)) {
34
+ Print.error('Source directory (/src) not found');
35
+ Print.info('Run "slice init" to initialize your project');
36
+ return false;
74
37
  }
38
+
39
+ return true;
75
40
  }
76
41
 
77
42
  /**
78
- * Minifica un archivo CSS
43
+ * Copia sliceConfig.json al directorio dist
79
44
  */
80
- async function minifyCSS(content, filename) {
81
- try {
82
- const cleanCSS = new CleanCSS(getMinificationOptions().css);
83
- const result = cleanCSS.minify(content);
84
-
85
- if (result.errors && result.errors.length > 0) {
86
- throw new Error(result.errors.join(', '));
87
- }
88
-
89
- const originalSize = Buffer.byteLength(content, 'utf8');
90
- const minifiedSize = Buffer.byteLength(result.styles, 'utf8');
91
- const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
92
-
93
- Print.minificationResult(filename, originalSize, minifiedSize, savings);
94
-
95
- return result.styles;
96
- } catch (error) {
97
- Print.error(`Error minifying ${filename}: ${error.message}`);
98
- throw error;
45
+ async function copySliceConfig() {
46
+ const srcConfig = path.join(__dirname, '../../../../src/sliceConfig.json');
47
+ const distConfig = path.join(__dirname, '../../../../dist/sliceConfig.json');
48
+
49
+ if (await fs.pathExists(srcConfig)) {
50
+ await fs.copy(srcConfig, distConfig);
51
+ Print.info('sliceConfig.json copied to dist');
99
52
  }
100
53
  }
101
54
 
102
55
  /**
103
- * Minifica un archivo HTML
56
+ * Procesa un directorio completo
104
57
  */
105
- async function minifyHTML(content, filename) {
106
- try {
107
- const result = await htmlMinifier.minify(content, getMinificationOptions().html);
108
-
109
- const originalSize = Buffer.byteLength(content, 'utf8');
110
- const minifiedSize = Buffer.byteLength(result, 'utf8');
111
- const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
112
-
113
- Print.minificationResult(filename, originalSize, minifiedSize, savings);
58
+ async function processDirectory(srcPath, distPath, baseSrcPath) {
59
+ const items = await fs.readdir(srcPath);
60
+
61
+ for (const item of items) {
62
+ const srcItemPath = path.join(srcPath, item);
63
+ const distItemPath = path.join(distPath, item);
64
+ const stat = await fs.stat(srcItemPath);
114
65
 
115
- return result;
116
- } catch (error) {
117
- Print.error(`Error minifying ${filename}: ${error.message}`);
118
- throw error;
66
+ if (stat.isDirectory()) {
67
+ await fs.ensureDir(distItemPath);
68
+ await processDirectory(srcItemPath, distItemPath, baseSrcPath);
69
+ } else {
70
+ await processFile(srcItemPath, distItemPath);
71
+ }
119
72
  }
120
73
  }
121
74
 
122
75
  /**
123
- * Procesa un archivo según su extensión
76
+ * Procesa un archivo individual
124
77
  */
125
- async function processFile(srcPath, destPath, relativePath) {
78
+ async function processFile(srcFilePath, distFilePath) {
79
+ const ext = path.extname(srcFilePath).toLowerCase();
80
+
126
81
  try {
127
- const content = await fs.readFile(srcPath, 'utf8');
128
- const ext = path.extname(srcPath).toLowerCase();
129
- let processedContent = content;
130
-
131
- switch (ext) {
132
- case '.js':
133
- processedContent = await minifyJavaScript(content, relativePath);
134
- break;
135
- case '.css':
136
- processedContent = await minifyCSS(content, relativePath);
137
- break;
138
- case '.html':
139
- processedContent = await minifyHTML(content, relativePath);
140
- break;
141
- default:
142
- // Para otros archivos (JSON, etc.), solo copiar
143
- await fs.copy(srcPath, destPath);
144
- return;
82
+ if (ext === '.js') {
83
+ await minifyJavaScript(srcFilePath, distFilePath);
84
+ } else if (ext === '.css') {
85
+ await minifyCSS(srcFilePath, distFilePath);
86
+ } else if (ext === '.html') {
87
+ await minifyHTML(srcFilePath, distFilePath);
88
+ } else {
89
+ // Copiar archivos que no necesitan minificación
90
+ await fs.copy(srcFilePath, distFilePath);
145
91
  }
146
-
147
- await fs.writeFile(destPath, processedContent, 'utf8');
148
-
149
92
  } catch (error) {
150
- Print.error(`Error processing ${relativePath}: ${error.message}`);
151
- throw error;
93
+ Print.error(`Processing ${path.basename(srcFilePath)}: ${error.message}`);
94
+ // Copiar archivo original si falla la minificación
95
+ await fs.copy(srcFilePath, distFilePath);
152
96
  }
153
97
  }
154
98
 
155
99
  /**
156
- * Copia y procesa recursivamente todos los archivos de src a dist
100
+ * Minifica archivos JavaScript
157
101
  */
158
- async function processDirectory(srcDir, distDir, baseSrcDir) {
159
- const items = await fs.readdir(srcDir);
102
+ async function minifyJavaScript(srcPath, distPath) {
103
+ const content = await fs.readFile(srcPath, 'utf8');
104
+ const originalSize = Buffer.byteLength(content, 'utf8');
160
105
 
161
- for (const item of items) {
162
- const srcPath = path.join(srcDir, item);
163
- const destPath = path.join(distDir, item);
164
- const relativePath = path.relative(baseSrcDir, srcPath);
165
-
166
- const stat = await fs.stat(srcPath);
167
-
168
- if (stat.isDirectory()) {
169
- await fs.ensureDir(destPath);
170
- await processDirectory(srcPath, destPath, baseSrcDir);
171
- } else {
172
- const ext = path.extname(srcPath).toLowerCase();
173
-
174
- // Procesar archivos que pueden ser minificados
175
- if (['.js', '.css', '.html'].includes(ext)) {
176
- await processFile(srcPath, destPath, relativePath);
177
- } else {
178
- // Copiar otros archivos sin modificar
179
- await fs.copy(srcPath, destPath);
180
- }
106
+ const result = UglifyJS.minify(content, {
107
+ compress: {
108
+ drop_console: false,
109
+ drop_debugger: true,
110
+ pure_funcs: ['console.log']
111
+ },
112
+ mangle: {
113
+ reserved: ['slice', 'Slice']
114
+ },
115
+ output: {
116
+ comments: false
181
117
  }
118
+ });
119
+
120
+ if (result.error) {
121
+ throw new Error(`UglifyJS error: ${result.error}`);
182
122
  }
123
+
124
+ await fs.writeFile(distPath, result.code, 'utf8');
125
+
126
+ const minifiedSize = Buffer.byteLength(result.code, 'utf8');
127
+ const savings = Math.round(((originalSize - minifiedSize) / originalSize) * 100);
128
+
129
+ Print.minificationResult(path.basename(srcPath), originalSize, minifiedSize, savings);
183
130
  }
184
131
 
185
132
  /**
186
- * Crea un bundle optimizado del archivo principal Slice.js
133
+ * Minifica archivos CSS
187
134
  */
188
- async function createOptimizedBundle() {
189
- try {
190
- Print.info('Creating optimized Slice.js bundle...');
191
-
192
- const slicePath = path.join(__dirname, '../../../../src/Slice/Slice.js');
193
- const distSlicePath = path.join(__dirname, '../../../../dist/Slice/Slice.js');
194
-
195
- if (!await fs.pathExists(slicePath)) {
196
- Print.warning('Slice.js main file not found, skipping bundle optimization');
197
- return;
198
- }
199
-
200
- const content = await fs.readFile(slicePath, 'utf8');
201
- const minifiedContent = await minifyJavaScript(content, 'Slice/Slice.js');
202
-
203
- await fs.ensureDir(path.dirname(distSlicePath));
204
- await fs.writeFile(distSlicePath, minifiedContent, 'utf8');
205
-
206
- Print.success('Optimized Slice.js bundle created');
207
-
208
- } catch (error) {
209
- Print.error(`Error creating optimized bundle: ${error.message}`);
210
- throw error;
135
+ async function minifyCSS(srcPath, distPath) {
136
+ const content = await fs.readFile(srcPath, 'utf8');
137
+ const originalSize = Buffer.byteLength(content, 'utf8');
138
+
139
+ const cleanCSS = new CleanCSS({
140
+ level: 2,
141
+ returnPromise: false
142
+ });
143
+
144
+ const result = cleanCSS.minify(content);
145
+
146
+ if (result.errors.length > 0) {
147
+ throw new Error(`CleanCSS errors: ${result.errors.join(', ')}`);
211
148
  }
149
+
150
+ await fs.writeFile(distPath, result.styles, 'utf8');
151
+
152
+ const minifiedSize = Buffer.byteLength(result.styles, 'utf8');
153
+ const savings = Math.round(((originalSize - minifiedSize) / originalSize) * 100);
154
+
155
+ Print.minificationResult(path.basename(srcPath), originalSize, minifiedSize, savings);
212
156
  }
213
157
 
214
158
  /**
215
- * Copia sliceConfig.json sin modificaciones
159
+ * Minifica archivos HTML
216
160
  */
217
- async function copySliceConfig() {
218
- try {
219
- const srcConfigPath = path.join(__dirname, '../../../../src/sliceConfig.json');
220
- const distConfigPath = path.join(__dirname, '../../../../dist/sliceConfig.json');
221
-
222
- if (await fs.pathExists(srcConfigPath)) {
223
- await fs.copy(srcConfigPath, distConfigPath);
224
- Print.success('sliceConfig.json copied to dist');
225
- } else {
226
- Print.warning('sliceConfig.json not found in src, skipping copy');
227
- }
228
- } catch (error) {
229
- Print.error(`Error copying sliceConfig.json: ${error.message}`);
230
- throw error;
161
+ async function minifyHTML(srcPath, distPath) {
162
+ const content = await fs.readFile(srcPath, 'utf8');
163
+ const originalSize = Buffer.byteLength(content, 'utf8');
164
+
165
+ const minified = await minify(content, {
166
+ collapseWhitespace: true,
167
+ removeComments: true,
168
+ removeRedundantAttributes: true,
169
+ removeScriptTypeAttributes: true,
170
+ removeStyleLinkTypeAttributes: true,
171
+ useShortDoctype: true,
172
+ minifyCSS: true,
173
+ minifyJS: true
174
+ });
175
+
176
+ await fs.writeFile(distPath, minified, 'utf8');
177
+
178
+ const minifiedSize = Buffer.byteLength(minified, 'utf8');
179
+ const savings = Math.round(((originalSize - minifiedSize) / originalSize) * 100);
180
+
181
+ Print.minificationResult(path.basename(srcPath), originalSize, minifiedSize, savings);
182
+ }
183
+
184
+ /**
185
+ * Crea un bundle optimizado del archivo principal
186
+ */
187
+ async function createOptimizedBundle() {
188
+ Print.buildProgress('Creating optimized bundle...');
189
+
190
+ const mainJSPath = path.join(__dirname, '../../../../dist/App/index.js');
191
+
192
+ if (await fs.pathExists(mainJSPath)) {
193
+ Print.success('Main bundle optimized');
194
+ } else {
195
+ Print.warning('No main JavaScript file found for bundling');
231
196
  }
232
197
  }
233
198
 
@@ -235,56 +200,76 @@ async function copySliceConfig() {
235
200
  * Genera estadísticas del build
236
201
  */
237
202
  async function generateBuildStats(srcDir, distDir) {
238
- try {
239
- Print.info('Generating build statistics...');
203
+ Print.buildProgress('Generating build statistics...');
204
+
205
+ const getDirectorySize = async (dirPath) => {
206
+ let totalSize = 0;
207
+ const items = await fs.readdir(dirPath);
240
208
 
241
- const calculateDirSize = async (dir) => {
242
- let totalSize = 0;
243
- const files = await fs.readdir(dir, { withFileTypes: true });
209
+ for (const item of items) {
210
+ const itemPath = path.join(dirPath, item);
211
+ const stat = await fs.stat(itemPath);
244
212
 
245
- for (const file of files) {
246
- const filePath = path.join(dir, file.name);
247
- if (file.isDirectory()) {
248
- totalSize += await calculateDirSize(filePath);
249
- } else {
250
- const stats = await fs.stat(filePath);
251
- totalSize += stats.size;
252
- }
213
+ if (stat.isDirectory()) {
214
+ totalSize += await getDirectorySize(itemPath);
215
+ } else {
216
+ totalSize += stat.size;
253
217
  }
254
- return totalSize;
255
- };
218
+ }
219
+
220
+ return totalSize;
221
+ };
256
222
 
257
- const srcSize = await calculateDirSize(srcDir);
258
- const distSize = await calculateDirSize(distDir);
259
- const savings = ((srcSize - distSize) / srcSize * 100).toFixed(1);
223
+ try {
224
+ const srcSize = await getDirectorySize(srcDir);
225
+ const distSize = await getDirectorySize(distDir);
226
+ const savings = Math.round(((srcSize - distSize) / srcSize) * 100);
260
227
 
261
228
  Print.newLine();
262
- Print.title('📊 Build Statistics');
263
- console.log(`📁 Source size: ${(srcSize / 1024).toFixed(1)} KB`);
264
- console.log(`📦 Production size: ${(distSize / 1024).toFixed(1)} KB`);
265
- console.log(`💾 Size reduction: ${savings}% saved`);
229
+ Print.info(`📊 Build Statistics:`);
230
+ console.log(` Source: ${(srcSize / 1024).toFixed(1)} KB`);
231
+ console.log(` Built: ${(distSize / 1024).toFixed(1)} KB`);
232
+ console.log(` Saved: ${savings}% smaller`);
266
233
 
267
234
  } catch (error) {
268
- Print.warning(`Could not generate build statistics: ${error.message}`);
235
+ Print.warning('Could not generate build statistics');
269
236
  }
270
237
  }
271
238
 
272
239
  /**
273
- * Función principal de build para producción
240
+ * Analiza el build sin construir
241
+ */
242
+ async function analyzeBuild() {
243
+ const distDir = path.join(__dirname, '../../../../dist');
244
+
245
+ if (!await fs.pathExists(distDir)) {
246
+ Print.error('No build found to analyze. Run "slice build" first.');
247
+ return;
248
+ }
249
+
250
+ Print.info('Analyzing production build...');
251
+ await generateBuildStats(
252
+ path.join(__dirname, '../../../../src'),
253
+ distDir
254
+ );
255
+ }
256
+
257
+ /**
258
+ * Función principal de build
274
259
  */
275
260
  export default async function buildProduction(options = {}) {
276
261
  const startTime = Date.now();
277
262
 
278
263
  try {
279
- Print.title('🚀 Building Slice.js project for production...');
264
+ Print.title('🔨 Building Slice.js project for production...');
280
265
  Print.newLine();
281
266
 
282
- // Verificar que existe src
283
267
  const srcDir = path.join(__dirname, '../../../../src');
284
268
  const distDir = path.join(__dirname, '../../../../dist');
285
269
 
270
+ // Verificar que existe el directorio src
286
271
  if (!await fs.pathExists(srcDir)) {
287
- throw new Error('src directory not found. Run "slice init" first.');
272
+ throw new Error('Source directory not found. Run "slice init" first.');
288
273
  }
289
274
 
290
275
  // 1. Limpiar directorio dist
@@ -320,10 +305,9 @@ export default async function buildProduction(options = {}) {
320
305
  Print.info('Your optimized project is ready in the /dist directory');
321
306
  Print.newLine();
322
307
  Print.info('Next steps:');
323
- console.log(' • The same /api folder serves both development and production');
324
- console.log(' • Update your Express server to serve from /dist instead of /src');
308
+ console.log(' • Use "npm run slice:start" to test the production build');
325
309
  console.log(' • Deploy both /api and /dist directories to your hosting provider');
326
- console.log(' • Use "slice build --serve" to preview the production build locally');
310
+ console.log(' • Use "slice build --serve" to preview the production build');
327
311
 
328
312
  return true;
329
313
 
@@ -334,52 +318,64 @@ export default async function buildProduction(options = {}) {
334
318
  }
335
319
 
336
320
  /**
337
- * Servidor de desarrollo para testing del build de producción
338
- * Usa Express como el servidor principal pero sirviendo desde /dist
321
+ * Servidor de preview para testing del build de producción
339
322
  */
340
- export async function serveProductionBuild(port = 3001) {
323
+ export async function serveProductionBuild(port) {
341
324
  try {
325
+ const config = loadConfig();
326
+ const defaultPort = config?.server?.port || 3001;
327
+ const finalPort = port || defaultPort;
328
+
342
329
  const distDir = path.join(__dirname, '../../../../dist');
343
330
 
344
331
  if (!await fs.pathExists(distDir)) {
345
332
  throw new Error('No production build found. Run "slice build" first.');
346
333
  }
347
334
 
348
- Print.info(`Starting production build server on port ${port}...`);
335
+ Print.info(`Starting production preview server on port ${finalPort}...`);
349
336
 
350
- // Implementar servidor estático simple que simula el comportamiento de la API
337
+ // Implementar servidor estático simple
351
338
  const express = await import('express');
352
339
  const app = express.default();
353
340
 
354
- // Servir archivos estáticos desde dist (equivalente a lo que hace la API con src)
341
+ // Servir archivos estáticos desde dist
355
342
  app.use(express.default.static(distDir));
356
343
 
357
344
  // SPA fallback - servir index.html para rutas no encontradas
358
345
  app.get('*', (req, res) => {
359
- const indexPath = path.join(distDir, 'index.html');
346
+ const indexPath = path.join(distDir, 'App/index.html');
347
+ const fallbackPath = path.join(distDir, 'index.html');
348
+
349
+ // Intentar primero App/index.html, luego index.html
360
350
  if (fs.existsSync(indexPath)) {
361
351
  res.sendFile(indexPath);
352
+ } else if (fs.existsSync(fallbackPath)) {
353
+ res.sendFile(fallbackPath);
362
354
  } else {
363
- res.status(404).send('Production build not found');
355
+ res.status(404).send('Production build index.html not found');
364
356
  }
365
357
  });
366
358
 
367
- app.listen(port, () => {
368
- Print.success(`Production build server running at http://localhost:${port}`);
359
+ app.listen(finalPort, () => {
360
+ Print.success(`Production preview server running at http://localhost:${finalPort}`);
369
361
  Print.info('Press Ctrl+C to stop the server');
370
- Print.info('This server simulates production environment using /dist files');
362
+ Print.info('This server previews your production build from /dist');
363
+ Print.warning('This is a preview server - use "npm run slice:start" for the full production server');
371
364
  });
372
365
 
373
366
  } catch (error) {
374
- Print.error(`Error starting production server: ${error.message}`);
367
+ Print.error(`Error starting production preview server: ${error.message}`);
375
368
  throw error;
376
369
  }
377
370
  }
378
371
 
379
372
  /**
380
- * Comando build con opciones - CORREGIDO
373
+ * Comando build con opciones
381
374
  */
382
375
  export async function buildCommand(options = {}) {
376
+ const config = loadConfig();
377
+ const defaultPort = config?.server?.port || 3001;
378
+
383
379
  // Verificar dependencias necesarias
384
380
  if (!await checkBuildDependencies()) {
385
381
  return false;
@@ -387,7 +383,7 @@ export async function buildCommand(options = {}) {
387
383
 
388
384
  if (options.serve) {
389
385
  // Solo servir build existente
390
- await serveProductionBuild(options.port);
386
+ await serveProductionBuild(options.port || defaultPort);
391
387
  return true;
392
388
  }
393
389
 
@@ -400,96 +396,12 @@ export async function buildCommand(options = {}) {
400
396
  // Build completo
401
397
  const success = await buildProduction(options);
402
398
 
403
- // Solo mostrar mensaje informativo, no ejecutar servidor automáticamente
404
399
  if (success && options.preview) {
405
400
  Print.newLine();
406
401
  Print.info('✨ Build completed successfully!');
407
- Print.info('💡 Use "slice build --serve" to preview the production build');
408
- Print.info('💡 Or "slice start" to start production server');
402
+ Print.info(`Starting preview server on port ${options.port || defaultPort}...`);
403
+ await serveProductionBuild(options.port || defaultPort);
409
404
  }
410
405
 
411
406
  return success;
412
- }
413
-
414
-
415
- /**
416
- * Verifica que las dependencias de build estén instaladas en el CLI
417
- */
418
- async function checkBuildDependencies() {
419
- try {
420
- Print.info('Checking build dependencies...');
421
-
422
- // Verificar dependencias en el CLI en lugar del proyecto
423
- const cliPackageJsonPath = path.join(__dirname, '../../package.json');
424
-
425
- if (!await fs.pathExists(cliPackageJsonPath)) {
426
- throw new Error('CLI package.json not found');
427
- }
428
-
429
- const cliPackageJson = await fs.readJson(cliPackageJsonPath);
430
- const deps = { ...cliPackageJson.dependencies, ...cliPackageJson.devDependencies };
431
-
432
- const requiredDeps = ['terser', 'clean-css', 'html-minifier-terser'];
433
- const missing = requiredDeps.filter(dep => !deps[dep]);
434
-
435
- if (missing.length > 0) {
436
- Print.error('Missing build dependencies in CLI:');
437
- missing.forEach(dep => console.log(` • ${dep}`));
438
- Print.newLine();
439
- Print.info('Please update slicejs-cli to the latest version:');
440
- console.log('npm install -g slicejs-cli@latest');
441
- return false;
442
- }
443
-
444
- Print.success('All build dependencies are available in CLI');
445
- return true;
446
-
447
- } catch (error) {
448
- Print.error(`Error checking dependencies: ${error.message}`);
449
- return false;
450
- }
451
- }
452
-
453
- /**
454
- * Analiza el tamaño y composición del build
455
- */
456
- async function analyzeBuild() {
457
- try {
458
- const distDir = path.join(__dirname, '../../../../dist');
459
-
460
- if (!await fs.pathExists(distDir)) {
461
- throw new Error('No production build found. Run "slice build" first.');
462
- }
463
-
464
- Print.title('📊 Build Analysis');
465
- Print.newLine();
466
-
467
- const analyzeDirectory = async (dir, prefix = '') => {
468
- const items = await fs.readdir(dir);
469
- let totalSize = 0;
470
-
471
- for (const item of items) {
472
- const itemPath = path.join(dir, item);
473
- const stat = await fs.stat(itemPath);
474
-
475
- if (stat.isDirectory()) {
476
- const dirSize = await analyzeDirectory(itemPath, `${prefix}${item}/`);
477
- totalSize += dirSize;
478
- } else {
479
- const size = (stat.size / 1024).toFixed(1);
480
- console.log(`📄 ${prefix}${item}: ${size} KB`);
481
- totalSize += stat.size;
482
- }
483
- }
484
-
485
- return totalSize;
486
- };
487
-
488
- const totalSize = await analyzeDirectory(distDir);
489
- Print.newLine();
490
- Print.info(`Total build size: ${(totalSize / 1024).toFixed(1)} KB`);
491
-
492
- } catch (error) {
493
- Print.error(`Error analyzing build: ${error.message}`);
494
- }
495
407
  }
@@ -1,4 +1,4 @@
1
- // commands/startServer/startServer.js
1
+ // commands/startServer/startServer.js - CON ARGUMENTOS
2
2
 
3
3
  import fs from 'fs-extra';
4
4
  import path from 'path';
@@ -8,6 +8,20 @@ import Print from '../Print.js';
8
8
 
9
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
10
 
11
+ /**
12
+ * Carga la configuración desde sliceConfig.json
13
+ */
14
+ const loadConfig = () => {
15
+ try {
16
+ const configPath = path.join(__dirname, '../../../../src/sliceConfig.json');
17
+ const rawData = fs.readFileSync(configPath, 'utf-8');
18
+ return JSON.parse(rawData);
19
+ } catch (error) {
20
+ Print.error(`Loading configuration: ${error.message}`);
21
+ return null;
22
+ }
23
+ };
24
+
11
25
  /**
12
26
  * Verifica si existe un build de producción
13
27
  */
@@ -27,7 +41,7 @@ async function checkDevelopmentStructure() {
27
41
  }
28
42
 
29
43
  /**
30
- * Inicia el servidor Node.js
44
+ * Inicia el servidor Node.js con argumentos
31
45
  */
32
46
  function startNodeServer(port, mode) {
33
47
  return new Promise((resolve, reject) => {
@@ -35,13 +49,20 @@ function startNodeServer(port, mode) {
35
49
 
36
50
  Print.info(`Starting ${mode} server on port ${port}...`);
37
51
 
38
- const serverProcess = spawn('node', [apiIndexPath], {
52
+ // Construir argumentos basados en el modo
53
+ const args = [apiIndexPath];
54
+ if (mode === 'production') {
55
+ args.push('--production');
56
+ } else {
57
+ args.push('--development');
58
+ }
59
+
60
+ const serverProcess = spawn('node', args, {
39
61
  stdio: 'inherit',
40
62
  env: {
41
63
  ...process.env,
42
- PORT: port,
43
- NODE_ENV: mode === 'production' ? 'production' : 'development',
44
- SLICE_CLI_MODE: 'true' // Flag para que api/index.js sepa que viene del CLI
64
+ PORT: port
65
+ // Ya no necesitamos NODE_ENV ni SLICE_CLI_MODE
45
66
  }
46
67
  });
47
68
 
@@ -57,26 +78,24 @@ function startNodeServer(port, mode) {
57
78
  process.exit(0);
58
79
  });
59
80
 
60
- // Manejar cierre del proceso
61
81
  process.on('SIGTERM', () => {
62
82
  serverProcess.kill('SIGTERM');
63
83
  });
64
84
 
65
- // El servidor se considera iniciado exitosamente después de un breve delay
66
85
  setTimeout(() => {
67
- Print.success(`${mode === 'production' ? 'Production' : 'Development'} server running at http://localhost:${port}`);
68
- Print.info(`Serving files from /${mode === 'production' ? 'dist' : 'src'} directory`);
69
- Print.info('Press Ctrl+C to stop the server');
70
86
  resolve(serverProcess);
71
- }, 1000);
87
+ }, 500);
72
88
  });
73
89
  }
74
90
 
75
91
  /**
76
- * Función principal para iniciar servidor - SIMPLIFICADA
92
+ * Función principal para iniciar servidor
77
93
  */
78
94
  export default async function startServer(options = {}) {
79
- const { mode = 'development', port = 3000 } = options;
95
+ const config = loadConfig();
96
+ const defaultPort = config?.server?.port || 3000;
97
+
98
+ const { mode = 'development', port = defaultPort } = options;
80
99
 
81
100
  try {
82
101
  Print.title(`🚀 Starting Slice.js ${mode} server...`);
@@ -97,7 +116,7 @@ export default async function startServer(options = {}) {
97
116
  Print.info('Development mode: serving files from /src with hot reload');
98
117
  }
99
118
 
100
- // Iniciar el servidor - api/index.js detectará automáticamente el modo
119
+ // Iniciar el servidor con argumentos
101
120
  await startNodeServer(port, mode);
102
121
 
103
122
  } catch (error) {
package/package.json CHANGED
@@ -1,28 +1,28 @@
1
- {
2
- "name": "slicejs-cli",
3
- "version": "2.2.4",
4
- "description": "Command client for developing web applications with Slice.js framework",
5
- "main": "client.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1",
8
- "postinstall": "node post.js"
9
- },
10
- "keywords": [
11
- "framework",
12
- "web",
13
- "client",
14
- "cli"
15
- ],
16
- "author": "vkneider",
17
- "type": "module",
18
- "license": "ISC",
19
- "dependencies": {
20
- "clean-css": "^5.3.3",
21
- "commander": "^12.0.0",
22
- "fs-extra": "^11.2.0",
23
- "html-minifier-terser": "^7.2.0",
24
- "inquirer": "^12.4.2",
25
- "slicejs-web-framework": "latest",
26
- "terser": "^5.43.1"
27
- }
28
- }
1
+ {
2
+ "name": "slicejs-cli",
3
+ "version": "2.2.6",
4
+ "description": "Command client for developing web applications with Slice.js framework",
5
+ "main": "client.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "postinstall": "node post.js"
9
+ },
10
+ "keywords": [
11
+ "framework",
12
+ "web",
13
+ "client",
14
+ "cli"
15
+ ],
16
+ "author": "vkneider",
17
+ "type": "module",
18
+ "license": "ISC",
19
+ "dependencies": {
20
+ "clean-css": "^5.3.3",
21
+ "commander": "^12.0.0",
22
+ "fs-extra": "^11.2.0",
23
+ "html-minifier-terser": "^7.2.0",
24
+ "inquirer": "^12.4.2",
25
+ "slicejs-web-framework": "latest",
26
+ "terser": "^5.43.1"
27
+ }
28
+ }
package/post.js CHANGED
@@ -24,8 +24,8 @@ fs.promises.access(projectPackageJsonPath, fs.constants.F_OK)
24
24
 
25
25
  // Main project commands
26
26
  projectPackageJson.scripts['slice:init'] = 'node node_modules/slicejs-cli/client.js init';
27
- projectPackageJson.scripts['slice:dev'] = 'node node_modules/slicejs-cli/client.js dev';
28
- projectPackageJson.scripts['slice:start'] = 'node node_modules/slicejs-cli/client.js start';
27
+ projectPackageJson.scripts['slice:dev'] = 'node api/index.js --development';
28
+ projectPackageJson.scripts['slice:start'] = 'node api/index.js --production';
29
29
  projectPackageJson.scripts['slice:build'] = 'node node_modules/slicejs-cli/client.js build';
30
30
  projectPackageJson.scripts['slice:version'] = 'node node_modules/slicejs-cli/client.js version';
31
31
  projectPackageJson.scripts['slice:update'] = 'node node_modules/slicejs-cli/client.js update';
@@ -50,9 +50,9 @@ fs.promises.access(projectPackageJsonPath, fs.constants.F_OK)
50
50
  projectPackageJson.scripts['slice:build-preview'] = 'node node_modules/slicejs-cli/client.js build --preview';
51
51
  projectPackageJson.scripts['slice:build-analyze'] = 'node node_modules/slicejs-cli/client.js build --analyze';
52
52
 
53
- // Legacy/compatibility commands
54
- projectPackageJson.scripts['run'] = 'node api/index.js';
55
- projectPackageJson.scripts['development'] = 'node node_modules/slicejs-cli/client.js dev';
53
+ // Legacy/compatibility commands - ACTUALIZADOS
54
+ projectPackageJson.scripts['run'] = 'node api/index.js --development';
55
+ projectPackageJson.scripts['development'] = 'node api/index.js --development';
56
56
 
57
57
  // Module configuration
58
58
  projectPackageJson.type = 'module';
@@ -91,6 +91,10 @@ fs.promises.access(projectPackageJsonPath, fs.constants.F_OK)
91
91
  console.log(' 3. npm run slice:build - Build for production');
92
92
  console.log(' 4. npm run slice:start - Test production build');
93
93
  console.log('\n💡 Tip: Use "slice:sync" to keep your components updated');
94
+ console.log('\n🔧 New argument-based system:');
95
+ console.log(' • slice:dev → node api/index.js --development');
96
+ console.log(' • slice:start → node api/index.js --production');
97
+ console.log(' • Arguments take precedence over environment variables');
94
98
  })
95
99
  .catch(err => {
96
100
  if (err.code === 'ENOENT') {
@@ -101,83 +105,56 @@ fs.promises.access(projectPackageJsonPath, fs.constants.F_OK)
101
105
  description: 'Slice.js project',
102
106
  main: 'api/index.js',
103
107
  scripts: {
104
- // Main workflow commands
108
+ // Main workflow commands - UPDATED with arguments
105
109
  'slice:init': 'node node_modules/slicejs-cli/client.js init',
106
- 'slice:dev': 'node node_modules/slicejs-cli/client.js dev',
107
- 'slice:start': 'node node_modules/slicejs-cli/client.js start',
110
+ 'slice:dev': 'node api/index.js --development',
111
+ 'slice:start': 'node api/index.js --production',
108
112
  'slice:build': 'node node_modules/slicejs-cli/client.js build',
109
113
  'slice:version': 'node node_modules/slicejs-cli/client.js version',
110
114
  'slice:update': 'node node_modules/slicejs-cli/client.js update',
111
115
 
112
- // Local components
116
+ // Local component commands
113
117
  'slice:create': 'node node_modules/slicejs-cli/client.js component create',
114
118
  'slice:list': 'node node_modules/slicejs-cli/client.js component list',
115
119
  'slice:delete': 'node node_modules/slicejs-cli/client.js component delete',
116
120
 
117
- // Official repository (shortcuts)
121
+ // Repository commands
118
122
  'slice:get': 'node node_modules/slicejs-cli/client.js get',
119
123
  'slice:browse': 'node node_modules/slicejs-cli/client.js browse',
120
124
  'slice:sync': 'node node_modules/slicejs-cli/client.js sync',
121
125
 
122
- // Detailed registry
123
- 'slice:registry-get': 'node node_modules/slicejs-cli/client.js registry get',
124
- 'slice:registry-list': 'node node_modules/slicejs-cli/client.js registry list',
125
- 'slice:registry-sync': 'node node_modules/slicejs-cli/client.js registry sync',
126
-
127
126
  // Build utilities
128
127
  'slice:build-serve': 'node node_modules/slicejs-cli/client.js build --serve',
129
128
  'slice:build-preview': 'node node_modules/slicejs-cli/client.js build --preview',
130
129
  'slice:build-analyze': 'node node_modules/slicejs-cli/client.js build --analyze',
131
130
 
132
- // Legacy
133
- 'run': 'node api/index.js',
134
- 'development': 'node node_modules/slicejs-cli/client.js dev'
131
+ // Legacy commands - UPDATED
132
+ 'run': 'node api/index.js --development',
133
+ 'development': 'node api/index.js --development'
135
134
  },
136
- keywords: ['slicejs', 'web-framework', 'components'],
137
- author: '',
138
- license: 'ISC',
139
135
  type: 'module',
140
136
  engines: {
141
137
  "node": ">=20.0.0"
142
138
  }
143
139
  };
144
140
 
145
- // Save the new package.json
146
141
  return fs.promises.writeFile(projectPackageJsonPath, JSON.stringify(defaultPackageJson, null, 2), 'utf8');
147
142
  } else {
148
- console.error('Error:', err);
149
143
  throw err;
150
144
  }
151
145
  })
152
146
  .then(() => {
153
- console.log('✅ Created package.json with SliceJS CLI commands.');
154
- console.log('\n🚀 Main workflow commands:');
155
- console.log(' npm run slice:init - Initialize Slice.js project');
156
- console.log(' npm run slice:dev - Start development server (serves from /src)');
157
- console.log(' npm run slice:build - Build for production (creates /dist)');
158
- console.log(' npm run slice:start - Start production server (serves from /dist)');
159
- console.log('\n📦 Component management:');
160
- console.log(' npm run slice:get Button - Get components from official repository');
161
- console.log(' npm run slice:browse - View all available components');
162
- console.log(' npm run slice:sync - Update local components to latest versions');
163
- console.log('\n⚙️ Local component management:');
164
- console.log(' npm run slice:create - Create local component');
165
- console.log(' npm run slice:list - List local components');
166
- console.log(' npm run slice:delete - Delete local component');
167
- console.log('\n🔧 Build utilities:');
168
- console.log(' npm run slice:build-serve - Build and serve immediately');
169
- console.log(' npm run slice:build-preview- Build and preview');
170
- console.log(' npm run slice:build-analyze- Analyze build size');
171
- console.log('\n🔧 Other utilities:');
172
- console.log(' npm run slice:version - View version information');
173
- console.log(' npm run slice:update - Check for available updates');
174
- console.log('\n🎯 Development workflow:');
175
- console.log(' 1. npm run slice:init - Initialize project');
176
- console.log(' 2. npm run slice:dev - Develop with hot reload');
177
- console.log(' 3. npm run slice:build - Build for production');
178
- console.log(' 4. npm run slice:start - Test production build');
179
- console.log('\n💡 Tip: Use "slice:sync" to keep your components updated');
147
+ console.log('✅ SliceJS CLI commands configured successfully');
148
+ console.log('\n🎯 Updated workflow:');
149
+ console.log(' npm run slice:dev → node api/index.js --development (serves /src)');
150
+ console.log(' npm run slice:start → node api/index.js --production (serves /dist)');
151
+ console.log('\n🔧 Benefits:');
152
+ console.log(' Clear argument-based mode detection');
153
+ console.log(' No confusion between src/dist directories');
154
+ console.log(' Maintains backward compatibility with NODE_ENV');
155
+ console.log(' More reliable and predictable behavior');
180
156
  })
181
157
  .catch(err => {
182
- console.error('Error creating package.json:', err);
183
- });
158
+ console.error('Error setting up package.json:', err.message);
159
+ process.exit(1);
160
+ });