slicejs-cli 2.2.5 → 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,274 +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 - CORREGIDAS
14
+ * Carga la configuración desde sliceConfig.json
15
15
  */
16
- const getMinificationOptions = () => ({
17
- js: {
18
- compress: {
19
- dead_code: true,
20
- drop_console: false, // NO remover console.log para evitar problemas
21
- drop_debugger: true,
22
- pure_funcs: [], // NO remover funciones específicas
23
- passes: 1, // Reducir pasadas para ser menos agresivo
24
- keep_classnames: true, // IMPORTANTE: Preservar nombres de clases
25
- keep_fnames: true // IMPORTANTE: Preservar nombres de funciones
26
- },
27
- mangle: {
28
- toplevel: false, // NO hacer mangle a nivel superior
29
- keep_classnames: true, // Preservar nombres de clases
30
- keep_fnames: true, // Preservar nombres de funciones
31
- reserved: [
32
- // Framework core
33
- 'Slice', 'Controller', 'StylesManager', 'ThemeManager', 'Logger',
34
- // Métodos importantes
35
- 'slice', 'build', 'init', 'attachTemplate', 'getComponent',
36
- // Eventos y propiedades de componentes
37
- 'constructor', 'connectedCallback', 'disconnectedCallback',
38
- 'attributeChangedCallback', 'adoptedCallback',
39
- // Variables comunes en componentes
40
- 'componentName', 'props', 'options', 'value', 'disabled',
41
- // HTML Elements y DOM
42
- 'HTMLElement', 'customElements', 'define', 'querySelector',
43
- 'querySelectorAll', 'addEventListener', 'removeEventListener',
44
- // Métodos de componentes Slice.js
45
- 'setComponentProps', 'componentCategories', 'templates',
46
- 'activeComponents', 'classes', 'requestedStyles'
47
- ]
48
- },
49
- output: {
50
- comments: false,
51
- beautify: false,
52
- keep_quoted_props: true // Preservar propiedades entre comillas
53
- },
54
- toplevel: false // NO optimizar a nivel superior
55
- },
56
- css: {
57
- level: 1, // Optimización moderada en lugar de agresiva
58
- returnPromise: false
59
- },
60
- html: {
61
- collapseWhitespace: true,
62
- removeComments: true,
63
- removeRedundantAttributes: true,
64
- removeEmptyAttributes: true,
65
- minifyCSS: false, // NO minificar CSS inline para evitar problemas
66
- minifyJS: false, // NO minificar JS inline para evitar problemas
67
- useShortDoctype: true,
68
- removeAttributeQuotes: false, // Mantener comillas en atributos
69
- removeOptionalTags: false // Mantener tags opcionales
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;
70
24
  }
71
- });
25
+ };
72
26
 
73
27
  /**
74
- * Minifica un archivo JavaScript de forma segura
28
+ * Verifica dependencias necesarias para el build
75
29
  */
76
- async function minifyJavaScript(content, filename) {
77
- try {
78
- // Para archivos de componentes, ser menos agresivo
79
- const isComponentFile = filename.includes('/Components/') || filename.includes('\\Components\\');
80
-
81
- let options = getMinificationOptions().js;
82
-
83
- if (isComponentFile) {
84
- // Configuración especial para archivos de componentes
85
- options = {
86
- ...options,
87
- compress: {
88
- ...options.compress,
89
- passes: 1,
90
- keep_classnames: true,
91
- keep_fnames: true
92
- },
93
- mangle: false // NO hacer mangle en archivos de componentes
94
- };
95
- }
96
-
97
- const result = await terserMinify(content, options);
98
-
99
- if (result.error) {
100
- throw result.error;
101
- }
102
-
103
- const originalSize = Buffer.byteLength(content, 'utf8');
104
- const minifiedSize = Buffer.byteLength(result.code, 'utf8');
105
- const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
106
-
107
- Print.minificationResult(filename, originalSize, minifiedSize, savings);
108
-
109
- return result.code;
110
- } catch (error) {
111
- Print.error(`Error minifying ${filename}: ${error.message}`);
112
- // En caso de error, devolver contenido original
113
- Print.warning(`Using original content for ${filename}`);
114
- return content;
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;
115
37
  }
38
+
39
+ return true;
116
40
  }
117
41
 
118
42
  /**
119
- * Minifica un archivo CSS
43
+ * Copia sliceConfig.json al directorio dist
120
44
  */
121
- async function minifyCSS(content, filename) {
122
- try {
123
- const cleanCSS = new CleanCSS(getMinificationOptions().css);
124
- const result = cleanCSS.minify(content);
125
-
126
- if (result.errors && result.errors.length > 0) {
127
- throw new Error(result.errors.join(', '));
128
- }
129
-
130
- const originalSize = Buffer.byteLength(content, 'utf8');
131
- const minifiedSize = Buffer.byteLength(result.styles, 'utf8');
132
- const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
133
-
134
- Print.minificationResult(filename, originalSize, minifiedSize, savings);
135
-
136
- return result.styles;
137
- } catch (error) {
138
- Print.error(`Error minifying ${filename}: ${error.message}`);
139
- 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');
140
52
  }
141
53
  }
142
54
 
143
55
  /**
144
- * Minifica un archivo HTML
56
+ * Procesa un directorio completo
145
57
  */
146
- async function minifyHTML(content, filename) {
147
- try {
148
- const result = await htmlMinifier.minify(content, getMinificationOptions().html);
149
-
150
- const originalSize = Buffer.byteLength(content, 'utf8');
151
- const minifiedSize = Buffer.byteLength(result, 'utf8');
152
- const savings = ((originalSize - minifiedSize) / originalSize * 100).toFixed(1);
153
-
154
- 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);
155
65
 
156
- return result;
157
- } catch (error) {
158
- Print.error(`Error minifying ${filename}: ${error.message}`);
159
- 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
+ }
160
72
  }
161
73
  }
162
74
 
163
75
  /**
164
- * Procesa un archivo según su extensión
76
+ * Procesa un archivo individual
165
77
  */
166
- async function processFile(srcPath, destPath, relativePath) {
78
+ async function processFile(srcFilePath, distFilePath) {
79
+ const ext = path.extname(srcFilePath).toLowerCase();
80
+
167
81
  try {
168
- const content = await fs.readFile(srcPath, 'utf8');
169
- const ext = path.extname(srcPath).toLowerCase();
170
- let processedContent = content;
171
-
172
- switch (ext) {
173
- case '.js':
174
- processedContent = await minifyJavaScript(content, relativePath);
175
- break;
176
- case '.css':
177
- processedContent = await minifyCSS(content, relativePath);
178
- break;
179
- case '.html':
180
- processedContent = await minifyHTML(content, relativePath);
181
- break;
182
- default:
183
- // Para otros archivos (JSON, etc.), solo copiar
184
- await fs.copy(srcPath, destPath);
185
- 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);
186
91
  }
187
-
188
- await fs.writeFile(destPath, processedContent, 'utf8');
189
-
190
92
  } catch (error) {
191
- Print.error(`Error processing ${relativePath}: ${error.message}`);
192
- 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);
193
96
  }
194
97
  }
195
98
 
196
99
  /**
197
- * Copia y procesa recursivamente todos los archivos de src a dist
100
+ * Minifica archivos JavaScript
198
101
  */
199
- async function processDirectory(srcDir, distDir, baseSrcDir) {
200
- 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');
201
105
 
202
- for (const item of items) {
203
- const srcPath = path.join(srcDir, item);
204
- const destPath = path.join(distDir, item);
205
- const relativePath = path.relative(baseSrcDir, srcPath);
206
-
207
- const stat = await fs.stat(srcPath);
208
-
209
- if (stat.isDirectory()) {
210
- await fs.ensureDir(destPath);
211
- await processDirectory(srcPath, destPath, baseSrcDir);
212
- } else {
213
- const ext = path.extname(srcPath).toLowerCase();
214
-
215
- // Procesar archivos que pueden ser minificados
216
- if (['.js', '.css', '.html'].includes(ext)) {
217
- await processFile(srcPath, destPath, relativePath);
218
- } else {
219
- // Copiar otros archivos sin modificar
220
- await fs.copy(srcPath, destPath);
221
- }
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
222
117
  }
118
+ });
119
+
120
+ if (result.error) {
121
+ throw new Error(`UglifyJS error: ${result.error}`);
223
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);
224
130
  }
225
131
 
226
132
  /**
227
- * Crea un bundle optimizado del archivo principal Slice.js
133
+ * Minifica archivos CSS
228
134
  */
229
- async function createOptimizedBundle() {
230
- try {
231
- Print.info('Creating optimized Slice.js bundle...');
232
-
233
- const slicePath = path.join(__dirname, '../../../../src/Slice/Slice.js');
234
- const distSlicePath = path.join(__dirname, '../../../../dist/Slice/Slice.js');
235
-
236
- if (!await fs.pathExists(slicePath)) {
237
- Print.warning('Slice.js main file not found, skipping bundle optimization');
238
- return;
239
- }
240
-
241
- const content = await fs.readFile(slicePath, 'utf8');
242
- const minifiedContent = await minifyJavaScript(content, 'Slice/Slice.js');
243
-
244
- await fs.ensureDir(path.dirname(distSlicePath));
245
- await fs.writeFile(distSlicePath, minifiedContent, 'utf8');
246
-
247
- Print.success('Optimized Slice.js bundle created');
248
-
249
- } catch (error) {
250
- Print.error(`Error creating optimized bundle: ${error.message}`);
251
- 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(', ')}`);
252
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);
253
156
  }
254
157
 
255
158
  /**
256
- * Copia sliceConfig.json sin modificaciones
159
+ * Minifica archivos HTML
257
160
  */
258
- async function copySliceConfig() {
259
- try {
260
- const srcConfigPath = path.join(__dirname, '../../../../src/sliceConfig.json');
261
- const distConfigPath = path.join(__dirname, '../../../../dist/sliceConfig.json');
262
-
263
- if (await fs.pathExists(srcConfigPath)) {
264
- await fs.copy(srcConfigPath, distConfigPath);
265
- Print.success('sliceConfig.json copied to dist');
266
- } else {
267
- Print.warning('sliceConfig.json not found in src, skipping copy');
268
- }
269
- } catch (error) {
270
- Print.error(`Error copying sliceConfig.json: ${error.message}`);
271
- 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');
272
196
  }
273
197
  }
274
198
 
@@ -276,56 +200,76 @@ async function copySliceConfig() {
276
200
  * Genera estadísticas del build
277
201
  */
278
202
  async function generateBuildStats(srcDir, distDir) {
279
- try {
280
- 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);
281
208
 
282
- const calculateDirSize = async (dir) => {
283
- let totalSize = 0;
284
- 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);
285
212
 
286
- for (const file of files) {
287
- const filePath = path.join(dir, file.name);
288
- if (file.isDirectory()) {
289
- totalSize += await calculateDirSize(filePath);
290
- } else {
291
- const stats = await fs.stat(filePath);
292
- totalSize += stats.size;
293
- }
213
+ if (stat.isDirectory()) {
214
+ totalSize += await getDirectorySize(itemPath);
215
+ } else {
216
+ totalSize += stat.size;
294
217
  }
295
- return totalSize;
296
- };
218
+ }
219
+
220
+ return totalSize;
221
+ };
297
222
 
298
- const srcSize = await calculateDirSize(srcDir);
299
- const distSize = await calculateDirSize(distDir);
300
- 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);
301
227
 
302
228
  Print.newLine();
303
- Print.title('📊 Build Statistics');
304
- console.log(`📁 Source size: ${(srcSize / 1024).toFixed(1)} KB`);
305
- console.log(`📦 Production size: ${(distSize / 1024).toFixed(1)} KB`);
306
- 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`);
307
233
 
308
234
  } catch (error) {
309
- Print.warning(`Could not generate build statistics: ${error.message}`);
235
+ Print.warning('Could not generate build statistics');
310
236
  }
311
237
  }
312
238
 
313
239
  /**
314
- * 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
315
259
  */
316
260
  export default async function buildProduction(options = {}) {
317
261
  const startTime = Date.now();
318
262
 
319
263
  try {
320
- Print.title('🚀 Building Slice.js project for production...');
264
+ Print.title('🔨 Building Slice.js project for production...');
321
265
  Print.newLine();
322
266
 
323
- // Verificar que existe src
324
267
  const srcDir = path.join(__dirname, '../../../../src');
325
268
  const distDir = path.join(__dirname, '../../../../dist');
326
269
 
270
+ // Verificar que existe el directorio src
327
271
  if (!await fs.pathExists(srcDir)) {
328
- throw new Error('src directory not found. Run "slice init" first.');
272
+ throw new Error('Source directory not found. Run "slice init" first.');
329
273
  }
330
274
 
331
275
  // 1. Limpiar directorio dist
@@ -361,10 +305,9 @@ export default async function buildProduction(options = {}) {
361
305
  Print.info('Your optimized project is ready in the /dist directory');
362
306
  Print.newLine();
363
307
  Print.info('Next steps:');
364
- console.log(' • The same /api folder serves both development and production');
365
- 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');
366
309
  console.log(' • Deploy both /api and /dist directories to your hosting provider');
367
- console.log(' • Use "slice build --serve" to preview the production build locally');
310
+ console.log(' • Use "slice build --serve" to preview the production build');
368
311
 
369
312
  return true;
370
313
 
@@ -375,52 +318,64 @@ export default async function buildProduction(options = {}) {
375
318
  }
376
319
 
377
320
  /**
378
- * Servidor de desarrollo para testing del build de producción
379
- * Usa Express como el servidor principal pero sirviendo desde /dist
321
+ * Servidor de preview para testing del build de producción
380
322
  */
381
- export async function serveProductionBuild(port = 3001) {
323
+ export async function serveProductionBuild(port) {
382
324
  try {
325
+ const config = loadConfig();
326
+ const defaultPort = config?.server?.port || 3001;
327
+ const finalPort = port || defaultPort;
328
+
383
329
  const distDir = path.join(__dirname, '../../../../dist');
384
330
 
385
331
  if (!await fs.pathExists(distDir)) {
386
332
  throw new Error('No production build found. Run "slice build" first.');
387
333
  }
388
334
 
389
- Print.info(`Starting production build server on port ${port}...`);
335
+ Print.info(`Starting production preview server on port ${finalPort}...`);
390
336
 
391
- // Implementar servidor estático simple que simula el comportamiento de la API
337
+ // Implementar servidor estático simple
392
338
  const express = await import('express');
393
339
  const app = express.default();
394
340
 
395
- // Servir archivos estáticos desde dist (equivalente a lo que hace la API con src)
341
+ // Servir archivos estáticos desde dist
396
342
  app.use(express.default.static(distDir));
397
343
 
398
344
  // SPA fallback - servir index.html para rutas no encontradas
399
345
  app.get('*', (req, res) => {
400
- 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
401
350
  if (fs.existsSync(indexPath)) {
402
351
  res.sendFile(indexPath);
352
+ } else if (fs.existsSync(fallbackPath)) {
353
+ res.sendFile(fallbackPath);
403
354
  } else {
404
- res.status(404).send('Production build not found');
355
+ res.status(404).send('Production build index.html not found');
405
356
  }
406
357
  });
407
358
 
408
- app.listen(port, () => {
409
- 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}`);
410
361
  Print.info('Press Ctrl+C to stop the server');
411
- 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');
412
364
  });
413
365
 
414
366
  } catch (error) {
415
- Print.error(`Error starting production server: ${error.message}`);
367
+ Print.error(`Error starting production preview server: ${error.message}`);
416
368
  throw error;
417
369
  }
418
370
  }
419
371
 
420
372
  /**
421
- * Comando build con opciones - CORREGIDO
373
+ * Comando build con opciones
422
374
  */
423
375
  export async function buildCommand(options = {}) {
376
+ const config = loadConfig();
377
+ const defaultPort = config?.server?.port || 3001;
378
+
424
379
  // Verificar dependencias necesarias
425
380
  if (!await checkBuildDependencies()) {
426
381
  return false;
@@ -428,7 +383,7 @@ export async function buildCommand(options = {}) {
428
383
 
429
384
  if (options.serve) {
430
385
  // Solo servir build existente
431
- await serveProductionBuild(options.port);
386
+ await serveProductionBuild(options.port || defaultPort);
432
387
  return true;
433
388
  }
434
389
 
@@ -441,96 +396,12 @@ export async function buildCommand(options = {}) {
441
396
  // Build completo
442
397
  const success = await buildProduction(options);
443
398
 
444
- // Solo mostrar mensaje informativo, no ejecutar servidor automáticamente
445
399
  if (success && options.preview) {
446
400
  Print.newLine();
447
401
  Print.info('✨ Build completed successfully!');
448
- Print.info('💡 Use "slice build --serve" to preview the production build');
449
- 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);
450
404
  }
451
405
 
452
406
  return success;
453
- }
454
-
455
-
456
- /**
457
- * Verifica que las dependencias de build estén instaladas en el CLI
458
- */
459
- async function checkBuildDependencies() {
460
- try {
461
- Print.info('Checking build dependencies...');
462
-
463
- // Verificar dependencias en el CLI en lugar del proyecto
464
- const cliPackageJsonPath = path.join(__dirname, '../../package.json');
465
-
466
- if (!await fs.pathExists(cliPackageJsonPath)) {
467
- throw new Error('CLI package.json not found');
468
- }
469
-
470
- const cliPackageJson = await fs.readJson(cliPackageJsonPath);
471
- const deps = { ...cliPackageJson.dependencies, ...cliPackageJson.devDependencies };
472
-
473
- const requiredDeps = ['terser', 'clean-css', 'html-minifier-terser'];
474
- const missing = requiredDeps.filter(dep => !deps[dep]);
475
-
476
- if (missing.length > 0) {
477
- Print.error('Missing build dependencies in CLI:');
478
- missing.forEach(dep => console.log(` • ${dep}`));
479
- Print.newLine();
480
- Print.info('Please update slicejs-cli to the latest version:');
481
- console.log('npm install -g slicejs-cli@latest');
482
- return false;
483
- }
484
-
485
- Print.success('All build dependencies are available in CLI');
486
- return true;
487
-
488
- } catch (error) {
489
- Print.error(`Error checking dependencies: ${error.message}`);
490
- return false;
491
- }
492
- }
493
-
494
- /**
495
- * Analiza el tamaño y composición del build
496
- */
497
- async function analyzeBuild() {
498
- try {
499
- const distDir = path.join(__dirname, '../../../../dist');
500
-
501
- if (!await fs.pathExists(distDir)) {
502
- throw new Error('No production build found. Run "slice build" first.');
503
- }
504
-
505
- Print.title('📊 Build Analysis');
506
- Print.newLine();
507
-
508
- const analyzeDirectory = async (dir, prefix = '') => {
509
- const items = await fs.readdir(dir);
510
- let totalSize = 0;
511
-
512
- for (const item of items) {
513
- const itemPath = path.join(dir, item);
514
- const stat = await fs.stat(itemPath);
515
-
516
- if (stat.isDirectory()) {
517
- const dirSize = await analyzeDirectory(itemPath, `${prefix}${item}/`);
518
- totalSize += dirSize;
519
- } else {
520
- const size = (stat.size / 1024).toFixed(1);
521
- console.log(`📄 ${prefix}${item}: ${size} KB`);
522
- totalSize += stat.size;
523
- }
524
- }
525
-
526
- return totalSize;
527
- };
528
-
529
- const totalSize = await analyzeDirectory(distDir);
530
- Print.newLine();
531
- Print.info(`Total build size: ${(totalSize / 1024).toFixed(1)} KB`);
532
-
533
- } catch (error) {
534
- Print.error(`Error analyzing build: ${error.message}`);
535
- }
536
407
  }
@@ -1,4 +1,4 @@
1
- // commands/startServer/startServer.js - VERSIÓN SIMPLIFICADA
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 - SIMPLIFICADO
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
 
@@ -50,7 +71,7 @@ function startNodeServer(port, mode) {
50
71
  reject(error);
51
72
  });
52
73
 
53
- // Manejar Ctrl+C - SIMPLIFICADO
74
+ // Manejar Ctrl+C
54
75
  process.on('SIGINT', () => {
55
76
  Print.info('Shutting down server...');
56
77
  serverProcess.kill('SIGINT');
@@ -61,7 +82,6 @@ function startNodeServer(port, mode) {
61
82
  serverProcess.kill('SIGTERM');
62
83
  });
63
84
 
64
- // NO mostrar mensajes duplicados - el api/index.js ya se encarga
65
85
  setTimeout(() => {
66
86
  resolve(serverProcess);
67
87
  }, 500);
@@ -69,10 +89,13 @@ function startNodeServer(port, mode) {
69
89
  }
70
90
 
71
91
  /**
72
- * Función principal para iniciar servidor - ULTRA SIMPLIFICADA
92
+ * Función principal para iniciar servidor
73
93
  */
74
94
  export default async function startServer(options = {}) {
75
- 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;
76
99
 
77
100
  try {
78
101
  Print.title(`🚀 Starting Slice.js ${mode} server...`);
@@ -93,7 +116,7 @@ export default async function startServer(options = {}) {
93
116
  Print.info('Development mode: serving files from /src with hot reload');
94
117
  }
95
118
 
96
- // Iniciar el servidor - api/index.js maneja todo automáticamente
119
+ // Iniciar el servidor con argumentos
97
120
  await startNodeServer(port, mode);
98
121
 
99
122
  } catch (error) {
package/package.json CHANGED
@@ -1,28 +1,28 @@
1
- {
2
- "name": "slicejs-cli",
3
- "version": "2.2.5",
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
+ });