versacompiler 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hrm/devMode.js +120 -23
- package/dist/index.js +219 -82
- package/dist/services/vueLoader.js +21 -19
- package/dist/utils/transformWithAcorn.js +316 -0
- package/dist/utils/utils.js +48 -48
- package/package.json +7 -5
package/dist/hrm/devMode.js
CHANGED
|
@@ -126,6 +126,7 @@ export async function reloadComponent(
|
|
|
126
126
|
) {
|
|
127
127
|
try {
|
|
128
128
|
const baseUrl = window.location.href;
|
|
129
|
+
// console.log(relativePath);
|
|
129
130
|
const newBaseUrl = new URL(baseUrl);
|
|
130
131
|
const urlOrigin = `${newBaseUrl.origin}/${relativePath}`;
|
|
131
132
|
const module = await import(`${urlOrigin}?t=${Date.now()}`);
|
|
@@ -193,13 +194,109 @@ export function debounce(func, waitFor) {
|
|
|
193
194
|
return debounced;
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
export async function reloadJS(
|
|
197
|
-
|
|
197
|
+
export async function reloadJS(pathWithTimestamp) {
|
|
198
|
+
// Extraer la ruta base sin el timestamp
|
|
199
|
+
const pathParts = pathWithTimestamp.split('?');
|
|
200
|
+
const basePath = pathParts[0];
|
|
201
|
+
|
|
202
|
+
const contenidoArchivo = await fetch(pathWithTimestamp).then(res =>
|
|
203
|
+
res.text(),
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
// Verificar la marca para recarga completa
|
|
207
|
+
if (contenidoArchivo.startsWith('//versaHRM-reloadFILE')) {
|
|
208
|
+
console.log(
|
|
209
|
+
`[HMR] Marca //versaHRM-reloadFILE detectada en ${basePath}. Recargando página completa.`,
|
|
210
|
+
);
|
|
211
|
+
window.location.reload();
|
|
212
|
+
return; // Detener procesamiento adicional para este archivo
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* La lógica anterior para createApp/mount ya no es necesaria aquí, la marca la cubre.
|
|
216
|
+
if (
|
|
217
|
+
contenidoArchivo.includes('createApp') ||
|
|
218
|
+
contenidoArchivo.includes('.mount')
|
|
219
|
+
) {
|
|
220
|
+
window.location.reload();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
// Verificar si tenemos una función de recarga registrada para este módulo
|
|
226
|
+
if (
|
|
227
|
+
window.__VERSA_HMR &&
|
|
228
|
+
window.__VERSA_HMR.modules &&
|
|
229
|
+
window.__VERSA_HMR.modules[basePath]
|
|
230
|
+
) {
|
|
231
|
+
console.log(
|
|
232
|
+
`[HMR] Usando sistema HMR interno para recargar: ${basePath}`,
|
|
233
|
+
);
|
|
234
|
+
try {
|
|
235
|
+
const result = await window.__VERSA_HMR.modules[basePath]();
|
|
236
|
+
return result;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error(
|
|
239
|
+
`[HMR] Error al recargar el módulo usando sistema HMR interno:`,
|
|
240
|
+
error,
|
|
241
|
+
);
|
|
242
|
+
// Si falla el sistema interno, intentamos el enfoque tradicional
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Si no hay una función específica, usar la lógica existente
|
|
247
|
+
try {
|
|
248
|
+
console.log(`[HMR] Intentando re-importar JS: ${pathWithTimestamp}`);
|
|
249
|
+
// La URL ya está completa y lista para usar.
|
|
250
|
+
// El `import()` dinámico usa la URL base del script actual si la ruta es relativa,
|
|
251
|
+
// o la URL tal cual si es absoluta (comenzando con / o http/https).
|
|
252
|
+
// Como pathWithTimestamp comienza con '/', se resolverá desde la raíz del host.
|
|
253
|
+
const newModule = await import(pathWithTimestamp);
|
|
254
|
+
console.log(
|
|
255
|
+
`[HMR] Módulo JS ${pathWithTimestamp} re-importado exitosamente.`,
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
// Lógica de ejemplo: si el módulo exporta una función 'onHotUpdate' o 'init', llamarla.
|
|
259
|
+
// Esto es una convención que tus módulos JS tendrían que seguir.
|
|
260
|
+
if (newModule && typeof newModule.onHotUpdate === 'function') {
|
|
261
|
+
console.log(
|
|
262
|
+
`[HMR] Llamando a onHotUpdate() para el módulo ${pathWithTimestamp}`,
|
|
263
|
+
);
|
|
264
|
+
newModule.onHotUpdate();
|
|
265
|
+
} else if (newModule && typeof newModule.init === 'function') {
|
|
266
|
+
// Alternativamente, una función 'init' si es más genérico
|
|
267
|
+
console.log(
|
|
268
|
+
`[HMR] Llamando a init() para el módulo ${pathWithTimestamp}`,
|
|
269
|
+
);
|
|
270
|
+
newModule.init();
|
|
271
|
+
} else if (newModule && typeof newModule.main === 'function') {
|
|
272
|
+
// O una función 'main'
|
|
273
|
+
console.log(
|
|
274
|
+
`[HMR] Llamando a main() para el módulo ${pathWithTimestamp}`,
|
|
275
|
+
);
|
|
276
|
+
newModule.main();
|
|
277
|
+
}
|
|
278
|
+
// Si no hay una función específica, la simple re-importación podría ser suficiente
|
|
279
|
+
// si el módulo se auto-ejecuta (ej. añade event listeners, modifica el DOM globalmente).
|
|
280
|
+
// ¡CUIDADO con efectos secundarios duplicados en este caso!
|
|
281
|
+
|
|
282
|
+
return null; // Indicar éxito
|
|
283
|
+
} catch (error) {
|
|
284
|
+
console.error(
|
|
285
|
+
`[HMR] Error al re-importar el módulo JS ${pathWithTimestamp}:`,
|
|
286
|
+
error,
|
|
287
|
+
);
|
|
288
|
+
// Aquí podrías decidir si mostrar un error en el overlay o, como último recurso, recargar.
|
|
289
|
+
// Por ahora, solo retornamos false para que el llamador (vueLoader.js) decida.
|
|
290
|
+
return {
|
|
291
|
+
msg: `Error al re-importar el módulo JS ${pathWithTimestamp}:`,
|
|
292
|
+
error,
|
|
293
|
+
}; // Indicar fallo
|
|
294
|
+
}
|
|
198
295
|
}
|
|
199
296
|
|
|
200
297
|
export function socketReload(app) {
|
|
201
298
|
if (window.___browserSync___?.socket) {
|
|
202
|
-
const socket = window.___browserSync___.socket;
|
|
299
|
+
// const socket = window.___browserSync___.socket;
|
|
203
300
|
// Configura el observer para actualizar el árbol de componentes en cada mutación relevante
|
|
204
301
|
if (app && app._container) {
|
|
205
302
|
currentComponentTree = buildComponentTree(app._instance);
|
|
@@ -209,27 +306,27 @@ export function socketReload(app) {
|
|
|
209
306
|
}
|
|
210
307
|
});
|
|
211
308
|
}
|
|
212
|
-
socket.on('vue:update', data => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
309
|
+
// socket.on('vue:update', data => {
|
|
310
|
+
// console.log('pasa');
|
|
311
|
+
// if (document.querySelector('#versa-hmr-error-overlay')) {
|
|
312
|
+
// window.location.reload();
|
|
313
|
+
// return;
|
|
314
|
+
// }
|
|
218
315
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
});
|
|
316
|
+
// const { component, relativePath, extension, type, timestamp } =
|
|
317
|
+
// data;
|
|
318
|
+
// if (extension === 'vue') {
|
|
319
|
+
// reloadComponent(
|
|
320
|
+
// app,
|
|
321
|
+
// component,
|
|
322
|
+
// `/${relativePath}`,
|
|
323
|
+
// type,
|
|
324
|
+
// extension,
|
|
325
|
+
// );
|
|
326
|
+
// } else {
|
|
327
|
+
// reloadJS(`/${relativePath}?t=${timestamp}`);
|
|
328
|
+
// }
|
|
329
|
+
// });
|
|
233
330
|
} else {
|
|
234
331
|
setTimeout(() => {
|
|
235
332
|
window.location.reload();
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import { linter } from './services/linter.js';
|
|
|
25
25
|
import { minifyJS } from './services/minify.js';
|
|
26
26
|
import { preCompileTS } from './services/typescript.js';
|
|
27
27
|
import { preCompileVue } from './services/vuejs.js';
|
|
28
|
+
import { transformModuleWithAcorn } from './utils/transformWithAcorn.js';
|
|
28
29
|
|
|
29
30
|
import { addImportEndJs, mapRuta, showTimingForHumans } from './utils/utils.js';
|
|
30
31
|
|
|
@@ -340,6 +341,10 @@ const estandarizaData = async data => {
|
|
|
340
341
|
data = await replaceAliasImportsAsync(data);
|
|
341
342
|
data = await addImportEndJs(data);
|
|
342
343
|
|
|
344
|
+
if (!isProd) {
|
|
345
|
+
data = await transformModuleWithAcorn(data);
|
|
346
|
+
}
|
|
347
|
+
|
|
343
348
|
return data;
|
|
344
349
|
};
|
|
345
350
|
|
|
@@ -348,26 +353,38 @@ const estandarizaData = async data => {
|
|
|
348
353
|
* @param {string} source - La ruta del archivo fuente.
|
|
349
354
|
* @param {string} destination - La ruta del archivo de destino.
|
|
350
355
|
*
|
|
351
|
-
* @returns {Promise<
|
|
356
|
+
* @returns {Promise<Object>} - Un objeto con información sobre la compilación.
|
|
352
357
|
*/
|
|
353
358
|
const compileJS = async (source, destination) => {
|
|
354
359
|
try {
|
|
355
|
-
const startTime = Date.now();
|
|
360
|
+
const startTime = Date.now();
|
|
361
|
+
const originalExtension = source.split('.').pop();
|
|
362
|
+
const baseName = path.basename(destination, path.extname(destination));
|
|
363
|
+
const finalFileName = baseName.endsWith('.js')
|
|
364
|
+
? baseName.slice(0, -3)
|
|
365
|
+
: baseName;
|
|
356
366
|
|
|
357
|
-
|
|
358
|
-
await log(chalk.blue(`🪄 :start compilation`));
|
|
367
|
+
await log(chalk.blue(`🪄 :Iniciando compilación de ${source}`));
|
|
359
368
|
|
|
360
369
|
let data = await readFile(source, 'utf-8');
|
|
361
|
-
if (!data) {
|
|
362
|
-
await error(
|
|
363
|
-
|
|
370
|
+
if (!data || data.trim().length === 0) {
|
|
371
|
+
await error(
|
|
372
|
+
chalk.yellow(
|
|
373
|
+
`⚠️ :Archivo fuente ${source} está vacío. No se procesará.`,
|
|
374
|
+
),
|
|
375
|
+
);
|
|
376
|
+
return {
|
|
377
|
+
contentWasWritten: false,
|
|
378
|
+
extension: originalExtension,
|
|
379
|
+
normalizedPath: destination,
|
|
380
|
+
fileName: finalFileName,
|
|
381
|
+
};
|
|
364
382
|
}
|
|
365
383
|
|
|
366
|
-
const extension = source.split('.').pop();
|
|
367
384
|
let resultVue = null;
|
|
368
|
-
if (
|
|
385
|
+
if (originalExtension === 'vue') {
|
|
369
386
|
vueFiles++;
|
|
370
|
-
await log(chalk.green(`💚 :
|
|
387
|
+
await log(chalk.green(`💚 :Precompilando VUE: ${source}`));
|
|
371
388
|
resultVue = await preCompileVue(data, source, isProd);
|
|
372
389
|
data = resultVue.data;
|
|
373
390
|
if (resultVue.error !== null) {
|
|
@@ -379,20 +396,25 @@ const compileJS = async (source, destination) => {
|
|
|
379
396
|
});
|
|
380
397
|
await error(
|
|
381
398
|
chalk.red(
|
|
382
|
-
`🚩 :Error durante la compilación Vue :${resultVue.error}\n`,
|
|
399
|
+
`🚩 :Error durante la compilación Vue para ${source} :${resultVue.error}\n`,
|
|
383
400
|
),
|
|
384
401
|
);
|
|
385
|
-
return
|
|
402
|
+
return {
|
|
403
|
+
contentWasWritten: false,
|
|
404
|
+
extension: originalExtension,
|
|
405
|
+
normalizedPath: destination,
|
|
406
|
+
fileName: finalFileName,
|
|
407
|
+
};
|
|
386
408
|
}
|
|
387
409
|
destination = destination.replace('.vue', '.js');
|
|
388
410
|
}
|
|
389
411
|
|
|
390
|
-
if (
|
|
412
|
+
if (originalExtension === 'ts' || resultVue?.lang === 'ts') {
|
|
391
413
|
tsFiles++;
|
|
392
|
-
await log(chalk.blue(`🔄️ :
|
|
414
|
+
await log(chalk.blue(`🔄️ :Precompilando TS: ${source}`));
|
|
393
415
|
const Resultdata = await preCompileTS(
|
|
394
416
|
data,
|
|
395
|
-
|
|
417
|
+
path.basename(source),
|
|
396
418
|
PATH_CONFIG_FILE,
|
|
397
419
|
);
|
|
398
420
|
if (Resultdata.error !== null) {
|
|
@@ -404,10 +426,15 @@ const compileJS = async (source, destination) => {
|
|
|
404
426
|
});
|
|
405
427
|
await error(
|
|
406
428
|
chalk.red(
|
|
407
|
-
`🚩 :Error durante la compilación TS: ${Resultdata.error}\n`,
|
|
429
|
+
`🚩 :Error durante la compilación TS para ${source}: ${Resultdata.error}\n`,
|
|
408
430
|
),
|
|
409
431
|
);
|
|
410
|
-
return
|
|
432
|
+
return {
|
|
433
|
+
contentWasWritten: false,
|
|
434
|
+
extension: originalExtension,
|
|
435
|
+
normalizedPath: destination,
|
|
436
|
+
fileName: finalFileName,
|
|
437
|
+
};
|
|
411
438
|
}
|
|
412
439
|
destination = destination.replace('.ts', '.js');
|
|
413
440
|
data = Resultdata.data;
|
|
@@ -415,9 +442,11 @@ const compileJS = async (source, destination) => {
|
|
|
415
442
|
|
|
416
443
|
data = await estandarizaData(data);
|
|
417
444
|
|
|
418
|
-
//
|
|
445
|
+
// const destinationDir = path.dirname(destination);
|
|
446
|
+
// await mkdir(destinationDir, { recursive: true });
|
|
447
|
+
// await writeFile(destination, data, 'utf-8');
|
|
419
448
|
|
|
420
|
-
await log(chalk.green(`🔍 :Validando Sintaxis`));
|
|
449
|
+
await log(chalk.green(`🔍 :Validando Sintaxis para ${source}`));
|
|
421
450
|
const resultAcorn = await checkSintaxysAcorn(data);
|
|
422
451
|
if (resultAcorn.error !== null) {
|
|
423
452
|
errorFiles++;
|
|
@@ -426,30 +455,44 @@ const compileJS = async (source, destination) => {
|
|
|
426
455
|
error: resultAcorn.error.message,
|
|
427
456
|
proceso: 'Validación Sintaxis',
|
|
428
457
|
});
|
|
429
|
-
|
|
458
|
+
await error(
|
|
459
|
+
chalk.red(
|
|
460
|
+
`🚩 :Error de sintaxis Acorn para ${source}: ${resultAcorn.error.message}\n`,
|
|
461
|
+
),
|
|
462
|
+
);
|
|
463
|
+
return {
|
|
464
|
+
contentWasWritten: false,
|
|
465
|
+
extension: originalExtension,
|
|
466
|
+
normalizedPath: destination,
|
|
467
|
+
fileName: finalFileName,
|
|
468
|
+
};
|
|
430
469
|
}
|
|
431
470
|
acornFiles++;
|
|
432
471
|
|
|
433
472
|
let result = null;
|
|
434
473
|
if (isProd) {
|
|
435
|
-
await log(chalk.blue(`🤖 :
|
|
436
|
-
result = await minifyJS(data,
|
|
474
|
+
await log(chalk.blue(`🤖 :Minificando ${source}`));
|
|
475
|
+
result = await minifyJS(data, path.basename(source), isProd);
|
|
437
476
|
} else {
|
|
438
477
|
result = { code: data };
|
|
439
478
|
}
|
|
440
|
-
await log(chalk.green(`📝 :
|
|
479
|
+
await log(chalk.green(`📝 :Intentando escribir ${destination}`));
|
|
441
480
|
|
|
442
|
-
if (result.code.length === 0) {
|
|
481
|
+
if (!result.code || result.code.trim().length === 0) {
|
|
443
482
|
await error(
|
|
444
483
|
chalk.yellow(
|
|
445
|
-
|
|
484
|
+
`⚠️ :Advertencia al compilar JS para ${source}: El archivo resultante está vacío. No se escribirá en disco.\n`,
|
|
446
485
|
),
|
|
447
486
|
);
|
|
448
|
-
|
|
487
|
+
return {
|
|
488
|
+
contentWasWritten: false,
|
|
489
|
+
extension: originalExtension,
|
|
490
|
+
normalizedPath: destination,
|
|
491
|
+
fileName: finalFileName,
|
|
492
|
+
};
|
|
449
493
|
} else {
|
|
450
494
|
if (!isProd) {
|
|
451
495
|
result.code = result.code.replaceAll('*/export', '*/\nexport');
|
|
452
|
-
result.code = result.code.replaceAll('*/export', '*/\nexport');
|
|
453
496
|
}
|
|
454
497
|
const destinationDir = path.dirname(destination);
|
|
455
498
|
await mkdir(destinationDir, { recursive: true });
|
|
@@ -458,24 +501,128 @@ const compileJS = async (source, destination) => {
|
|
|
458
501
|
const endTime = Date.now();
|
|
459
502
|
const elapsedTime = showTimingForHumans(endTime - startTime);
|
|
460
503
|
await log(
|
|
461
|
-
chalk.gray(
|
|
504
|
+
chalk.gray(
|
|
505
|
+
`✅ :Compilación exitosa para ${finalFileName} (${elapsedTime}) \n`,
|
|
506
|
+
),
|
|
462
507
|
);
|
|
463
508
|
successfulFiles++;
|
|
509
|
+
return {
|
|
510
|
+
contentWasWritten: true,
|
|
511
|
+
extension: originalExtension,
|
|
512
|
+
normalizedPath: destination,
|
|
513
|
+
fileName: finalFileName,
|
|
514
|
+
};
|
|
464
515
|
}
|
|
465
516
|
} catch (errora) {
|
|
466
517
|
errorFiles++;
|
|
518
|
+
const ext = source.split('.').pop() || 'unknown';
|
|
519
|
+
const fName = path.basename(source, path.extname(source));
|
|
467
520
|
errorList.push({
|
|
468
521
|
file: source,
|
|
469
522
|
error: errora.message,
|
|
470
|
-
proceso: 'Compilación JS',
|
|
523
|
+
proceso: 'Compilación JS (Catch General)',
|
|
471
524
|
});
|
|
472
525
|
await error(
|
|
473
|
-
chalk.red(
|
|
474
|
-
|
|
526
|
+
chalk.red(
|
|
527
|
+
`🚩 :Error catastrófico durante la compilación JS para ${source}: ${errora.message}\n`,
|
|
528
|
+
),
|
|
529
|
+
errora.stack,
|
|
530
|
+
);
|
|
531
|
+
return {
|
|
532
|
+
contentWasWritten: false,
|
|
533
|
+
extension: ext,
|
|
534
|
+
normalizedPath: destination || source,
|
|
535
|
+
fileName: fName,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Compila un archivo dado su ruta.
|
|
542
|
+
* @param {string} path - La ruta del archivo a compilar.
|
|
543
|
+
* @returns {Promise<Object>} - Un objeto con información sobre la compilación.
|
|
544
|
+
*/
|
|
545
|
+
const compile = async filePath => {
|
|
546
|
+
if (!filePath || typeof filePath !== 'string') {
|
|
547
|
+
console.error(
|
|
548
|
+
chalk.red('⚠️ :Ruta inválida proporcionada a compile():', filePath),
|
|
475
549
|
);
|
|
550
|
+
return {
|
|
551
|
+
contentWasWritten: false,
|
|
552
|
+
extension: null,
|
|
553
|
+
normalizedPath: filePath,
|
|
554
|
+
fileName: null,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
if (filePath.includes('.d.ts')) {
|
|
558
|
+
return {
|
|
559
|
+
contentWasWritten: false,
|
|
560
|
+
extension: 'd.ts',
|
|
561
|
+
normalizedPath: filePath,
|
|
562
|
+
fileName: path.basename(filePath),
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const normalizedPathSource = path.normalize(filePath).replace(/\\/g, '/');
|
|
567
|
+
const sourceForDist = normalizedPathSource.startsWith('./')
|
|
568
|
+
? normalizedPathSource
|
|
569
|
+
: `./${normalizedPathSource}`;
|
|
570
|
+
const outputPath = sourceForDist.replace(PATH_SOURCE, PATH_DIST);
|
|
571
|
+
const finalOutputJsPath = outputPath.replace(/\.(vue|ts)$/, '.js');
|
|
572
|
+
|
|
573
|
+
console.log(
|
|
574
|
+
chalk.green(`🔜 :Fuente para compilar: ${normalizedPathSource}`),
|
|
575
|
+
);
|
|
576
|
+
console.log(chalk.green(`🔚 :Destino potencial: ${finalOutputJsPath}`));
|
|
577
|
+
|
|
578
|
+
if (outputPath) {
|
|
579
|
+
return await compileJS(normalizedPathSource, finalOutputJsPath);
|
|
580
|
+
} else {
|
|
581
|
+
const ext = normalizedPathSource.split('.').pop() || null;
|
|
582
|
+
const fName = path.basename(
|
|
583
|
+
normalizedPathSource,
|
|
584
|
+
path.extname(normalizedPathSource),
|
|
585
|
+
);
|
|
586
|
+
await log(
|
|
587
|
+
chalk.yellow(
|
|
588
|
+
`⚠️ :Tipo de archivo no reconocido o ruta de salida no determinada para: ${normalizedPathSource}, extensión: ${ext}`,
|
|
589
|
+
),
|
|
590
|
+
);
|
|
591
|
+
return {
|
|
592
|
+
contentWasWritten: false,
|
|
593
|
+
extension: ext,
|
|
594
|
+
normalizedPath: finalOutputJsPath,
|
|
595
|
+
fileName: fName,
|
|
596
|
+
};
|
|
476
597
|
}
|
|
477
598
|
};
|
|
478
599
|
|
|
600
|
+
/**
|
|
601
|
+
* Emite cambios a través de BrowserSync.
|
|
602
|
+
* @param {Object} bs - Instancia de BrowserSync.
|
|
603
|
+
* @param {string} extension - Extensión del archivo.
|
|
604
|
+
* @param {string} normalizedPath - Ruta normalizada del archivo.
|
|
605
|
+
* @param {string} fileName - Nombre del archivo.
|
|
606
|
+
* @param {string} type - Tipo de cambio (add, change, delete).
|
|
607
|
+
*/
|
|
608
|
+
const emitirCambios = async (bs, extension, normalizedPath, fileName, type) => {
|
|
609
|
+
const serverRelativePath = path
|
|
610
|
+
.normalize(normalizedPath)
|
|
611
|
+
.replace(/^\\|^\//, '')
|
|
612
|
+
.replace(/\\/g, '/');
|
|
613
|
+
|
|
614
|
+
bs.sockets.emit('vue:update', {
|
|
615
|
+
component: fileName,
|
|
616
|
+
timestamp: Date.now(),
|
|
617
|
+
relativePath: serverRelativePath,
|
|
618
|
+
extension,
|
|
619
|
+
type,
|
|
620
|
+
});
|
|
621
|
+
console.log(
|
|
622
|
+
`📡 : Emitiendo evento 'vue:update' para ${fileName} (${type}) -> ${serverRelativePath} \n`,
|
|
623
|
+
);
|
|
624
|
+
};
|
|
625
|
+
|
|
479
626
|
async function generateTailwindCSS(_filePath = null) {
|
|
480
627
|
if (!tailwindcss) {
|
|
481
628
|
return;
|
|
@@ -496,42 +643,6 @@ async function generateTailwindCSS(_filePath = null) {
|
|
|
496
643
|
});
|
|
497
644
|
}
|
|
498
645
|
|
|
499
|
-
/**
|
|
500
|
-
* Compila un archivo dado su ruta.
|
|
501
|
-
* @param {string} path - La ruta del archivo a compilar.
|
|
502
|
-
*/
|
|
503
|
-
const compile = async filePath => {
|
|
504
|
-
if (!filePath || typeof filePath !== 'string') {
|
|
505
|
-
console.error(chalk.red('⚠️ :Ruta inválida:', filePath));
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
if (filePath.includes('.d.ts')) {
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
const normalizedPath = path.normalize(filePath).replace(/\\/g, '/'); // Normalizar la ruta para que use barras inclinadas hacia adelante
|
|
512
|
-
const filePathForReplate = `./${normalizedPath}`;
|
|
513
|
-
const outputPath = filePathForReplate.replace(PATH_SOURCE, PATH_DIST);
|
|
514
|
-
const outFileJs = outputPath.replace('.ts', '.js').replace('.vue', '.js');
|
|
515
|
-
|
|
516
|
-
console.log(chalk.green(`🔜 :Source ${filePathForReplate}`));
|
|
517
|
-
console.log(chalk.green(`🔚 :destination ${outFileJs}`));
|
|
518
|
-
|
|
519
|
-
const extension = normalizedPath.split('.').pop();
|
|
520
|
-
//sólo el filename sin extesion
|
|
521
|
-
const fileName = path
|
|
522
|
-
.basename(normalizedPath)
|
|
523
|
-
.replace('.vue', '')
|
|
524
|
-
.replace('.ts', '')
|
|
525
|
-
.replace('.js', '');
|
|
526
|
-
|
|
527
|
-
if (outputPath) {
|
|
528
|
-
await compileJS(normalizedPath, outputPath);
|
|
529
|
-
} else {
|
|
530
|
-
await log(chalk.yellow(`⚠️ :Tipo no reconocido: ${extension}`));
|
|
531
|
-
}
|
|
532
|
-
return { extension, normalizedPath: path.normalize(outFileJs), fileName };
|
|
533
|
-
};
|
|
534
|
-
|
|
535
646
|
/**
|
|
536
647
|
* Compila todos los archivos en los directorios de origen.
|
|
537
648
|
*/
|
|
@@ -616,17 +727,6 @@ const compileAll = async () => {
|
|
|
616
727
|
}
|
|
617
728
|
};
|
|
618
729
|
|
|
619
|
-
const emitirCambios = async (bs, extension, normalizedPath, fileName, type) => {
|
|
620
|
-
bs.sockets.emit('vue:update', {
|
|
621
|
-
component: fileName,
|
|
622
|
-
timestamp: Date.now(),
|
|
623
|
-
relativePath: normalizedPath,
|
|
624
|
-
extension,
|
|
625
|
-
type,
|
|
626
|
-
});
|
|
627
|
-
console.log(`📡 : Emitiendo evento 'vue:update' para ${fileName} \n`);
|
|
628
|
-
};
|
|
629
|
-
|
|
630
730
|
/**
|
|
631
731
|
* Inicializa el proceso de compilación y observación de archivos.
|
|
632
732
|
*/
|
|
@@ -652,19 +752,47 @@ const initChokidar = async () => {
|
|
|
652
752
|
// Evento cuando se añade un archivo
|
|
653
753
|
watcher.on('add', async filePath => {
|
|
654
754
|
await generateTailwindCSS(filePath);
|
|
655
|
-
const
|
|
755
|
+
const result = await compile(
|
|
656
756
|
path.normalize(filePath).replace(/\\/g, '/'),
|
|
657
757
|
);
|
|
658
|
-
|
|
758
|
+
if (result && result.contentWasWritten) {
|
|
759
|
+
emitirCambios(
|
|
760
|
+
bs,
|
|
761
|
+
result.extension,
|
|
762
|
+
result.normalizedPath,
|
|
763
|
+
result.fileName,
|
|
764
|
+
'add',
|
|
765
|
+
);
|
|
766
|
+
} else {
|
|
767
|
+
console.log(
|
|
768
|
+
chalk.yellow(
|
|
769
|
+
`[HMR] No se emite evento para archivo nuevo no escrito o vacío: ${filePath}. Razón: contentWasWritten es false o resultado inválido.`,
|
|
770
|
+
),
|
|
771
|
+
);
|
|
772
|
+
}
|
|
659
773
|
});
|
|
660
774
|
|
|
661
775
|
// Evento cuando se modifica un archivo
|
|
662
776
|
watcher.on('change', async filePath => {
|
|
663
777
|
await generateTailwindCSS(filePath);
|
|
664
|
-
const
|
|
778
|
+
const result = await compile(
|
|
665
779
|
path.normalize(filePath).replace(/\\/g, '/'),
|
|
666
780
|
);
|
|
667
|
-
|
|
781
|
+
if (result && result.contentWasWritten) {
|
|
782
|
+
emitirCambios(
|
|
783
|
+
bs,
|
|
784
|
+
result.extension,
|
|
785
|
+
result.normalizedPath,
|
|
786
|
+
result.fileName,
|
|
787
|
+
'change',
|
|
788
|
+
);
|
|
789
|
+
} else {
|
|
790
|
+
console.log(
|
|
791
|
+
chalk.yellow(
|
|
792
|
+
`[HMR] No se emite evento para archivo modificado a vacío, con errores, o no escrito: ${filePath}. Razón: contentWasWritten es false o resultado inválido.`,
|
|
793
|
+
),
|
|
794
|
+
);
|
|
795
|
+
}
|
|
668
796
|
});
|
|
669
797
|
|
|
670
798
|
// Evento cuando se elimina un archivo
|
|
@@ -749,6 +877,15 @@ const initChokidar = async () => {
|
|
|
749
877
|
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
750
878
|
res.setHeader('Access-Control-Max-Age', '3600');
|
|
751
879
|
|
|
880
|
+
if (req.url.endsWith('.js')) {
|
|
881
|
+
res.setHeader(
|
|
882
|
+
'Cache-Control',
|
|
883
|
+
'no-cache, no-store, must-revalidate',
|
|
884
|
+
);
|
|
885
|
+
res.setHeader('Pragma', 'no-cache');
|
|
886
|
+
res.setHeader('Expires', '0');
|
|
887
|
+
}
|
|
888
|
+
|
|
752
889
|
//para redigir a la ubicación correcta
|
|
753
890
|
if (req.url === '/__versa/vueLoader.js') {
|
|
754
891
|
// Busca vueLoader.js en la carpeta de salida configurada
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
let
|
|
2
|
-
getInstancia,
|
|
1
|
+
let getInstancia,
|
|
3
2
|
getVueInstance,
|
|
4
3
|
showErrorOverlay,
|
|
5
4
|
hideErrorOverlay,
|
|
@@ -12,7 +11,6 @@ let socketReload,
|
|
|
12
11
|
// Importa todas las dependencias HMR necesarias aquí
|
|
13
12
|
// CORREGIR RUTA DE IMPORTACIÓN PARA devMode.js
|
|
14
13
|
const devModeModule = await import('./hrm/devMode.js');
|
|
15
|
-
socketReload = devModeModule.socketReload;
|
|
16
14
|
reloadComponent = devModeModule.reloadComponent;
|
|
17
15
|
reloadJS = devModeModule.reloadJS;
|
|
18
16
|
|
|
@@ -161,20 +159,20 @@ const initSocket = async (retries = 0) => {
|
|
|
161
159
|
'[HMR] hideErrorOverlay no es una función al momento de la conexión',
|
|
162
160
|
);
|
|
163
161
|
}
|
|
164
|
-
|
|
165
|
-
if (vueAppInstance && vueAppInstance._instance) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
} else {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
162
|
+
await waitForVueInstance();
|
|
163
|
+
// if (vueAppInstance && vueAppInstance._instance) {
|
|
164
|
+
// if (typeof socketReload === 'function') {
|
|
165
|
+
// socketReload(vueAppInstance);
|
|
166
|
+
// } else {
|
|
167
|
+
// console.warn(
|
|
168
|
+
// '[HMR] socketReload no es una función al momento de la conexión',
|
|
169
|
+
// );
|
|
170
|
+
// }
|
|
171
|
+
// } else {
|
|
172
|
+
// console.error(
|
|
173
|
+
// '❌ Versa HMR: Instancia de Vue no encontrada después de la conexión del socket',
|
|
174
|
+
// );
|
|
175
|
+
// }
|
|
178
176
|
console.log('✔️ Versa HMR: Socket conectado');
|
|
179
177
|
});
|
|
180
178
|
|
|
@@ -238,8 +236,9 @@ const initSocket = async (retries = 0) => {
|
|
|
238
236
|
}
|
|
239
237
|
|
|
240
238
|
try {
|
|
239
|
+
let result;
|
|
241
240
|
if (extension === 'vue') {
|
|
242
|
-
|
|
241
|
+
result = await reloadComponent(
|
|
243
242
|
appInstance,
|
|
244
243
|
component,
|
|
245
244
|
`${relativePath}`,
|
|
@@ -251,7 +250,10 @@ const initSocket = async (retries = 0) => {
|
|
|
251
250
|
}
|
|
252
251
|
} else {
|
|
253
252
|
// Asumiendo que reloadJS existe
|
|
254
|
-
await reloadJS(`/${relativePath}?t=${timestamp}`);
|
|
253
|
+
result = await reloadJS(`/${relativePath}?t=${timestamp}`);
|
|
254
|
+
if (result && result.msg) {
|
|
255
|
+
throw new Error(result.msg);
|
|
256
|
+
}
|
|
255
257
|
}
|
|
256
258
|
} catch (hmrError) {
|
|
257
259
|
const errorMsg = `HMR falló para ${relativePath}`;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import * as acorn from 'acorn';
|
|
2
|
+
|
|
3
|
+
function generateHMRBlock(imports) {
|
|
4
|
+
let moduleRegistrationBlocks = [];
|
|
5
|
+
|
|
6
|
+
imports.default.forEach(imp => {
|
|
7
|
+
moduleRegistrationBlocks.push(
|
|
8
|
+
`window.__VERSA_HMR.modules['${imp.filePath}'] = async () => {\n` +
|
|
9
|
+
` try {\n` +
|
|
10
|
+
` ${imp.varName} = (await importWithTimestamp('${imp.filePath}')).default;\n` +
|
|
11
|
+
` console.log('[HMR] Módulo ${imp.filePath} (default) recargado');\n` +
|
|
12
|
+
` return true;\n` +
|
|
13
|
+
` } catch (e) {\n` +
|
|
14
|
+
` console.error('[HMR] Error recargando ${imp.filePath}', e);\n` +
|
|
15
|
+
` return false;\n` +
|
|
16
|
+
` }\n` +
|
|
17
|
+
` };`,
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
imports.namespace.forEach(imp => {
|
|
22
|
+
moduleRegistrationBlocks.push(
|
|
23
|
+
`window.__VERSA_HMR.modules['${imp.filePath}'] = async () => {\n` +
|
|
24
|
+
` try {\n` +
|
|
25
|
+
` ${imp.varName} = await importWithTimestamp('${imp.filePath}');\n` +
|
|
26
|
+
` console.log('[HMR] Módulo ${imp.filePath} (namespace) recargado');\n` +
|
|
27
|
+
` return true;\n` +
|
|
28
|
+
` } catch (e) {\n` +
|
|
29
|
+
` console.error('[HMR] Error recargando ${imp.filePath}', e);\n` +
|
|
30
|
+
` return false;\n` +
|
|
31
|
+
` }\n` +
|
|
32
|
+
` };`,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
imports.named.forEach(imp => {
|
|
37
|
+
moduleRegistrationBlocks.push(
|
|
38
|
+
`window.__VERSA_HMR.modules['${imp.filePath}'] = async () => {\n` +
|
|
39
|
+
` try {\n` +
|
|
40
|
+
` ({ ${imp.namedExports} } = await importWithTimestamp('${imp.filePath}'));\n` +
|
|
41
|
+
` console.log('[HMR] Módulo ${imp.filePath} (named) recargado');\n` +
|
|
42
|
+
` return true;\n` +
|
|
43
|
+
` } catch (e) {\n` +
|
|
44
|
+
` console.error('[HMR] Error recargando ${imp.filePath}', e);\n` +
|
|
45
|
+
` return false;\n` +
|
|
46
|
+
` }\n` +
|
|
47
|
+
` };`,
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (moduleRegistrationBlocks.length === 0) return '';
|
|
52
|
+
|
|
53
|
+
// Se incluye la definición de importWithTimestamp y la inicialización de __VERSA_HMR
|
|
54
|
+
// solo si hay módulos que registrar.
|
|
55
|
+
return `
|
|
56
|
+
const importWithTimestamp = (path) => import(path);
|
|
57
|
+
window.__VERSA_HMR = window.__VERSA_HMR || {};
|
|
58
|
+
window.__VERSA_HMR.modules = window.__VERSA_HMR.modules || {};
|
|
59
|
+
${moduleRegistrationBlocks.join('\n ')}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Función auxiliar para obtener nombres de _resolveComponent
|
|
63
|
+
const getResolvedComponents = codeString => {
|
|
64
|
+
const resolved = new Set();
|
|
65
|
+
const resolveComponentRegex =
|
|
66
|
+
/_resolveComponent\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
67
|
+
let match;
|
|
68
|
+
while ((match = resolveComponentRegex.exec(codeString)) !== null) {
|
|
69
|
+
resolved.add(match[1]);
|
|
70
|
+
}
|
|
71
|
+
return resolved;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Transforma código fuente JS/TS usando Acorn AST.
|
|
76
|
+
* Reconstruye el código separando imports, exports, funciones y bloques ejecutables.
|
|
77
|
+
* - Convierte imports estáticos en dinámicos
|
|
78
|
+
* - Preserva exports y estructura
|
|
79
|
+
* - Inserta bloque HMR solo si hay defineComponent y imports dinámicos
|
|
80
|
+
*
|
|
81
|
+
* @param {string} code - El código fuente a analizar.
|
|
82
|
+
* @returns {string} - El nuevo código transformado.
|
|
83
|
+
*
|
|
84
|
+
* Ejemplo de uso:
|
|
85
|
+
* const nuevoCodigo = transformModuleWithAcorn(codigoFuente);
|
|
86
|
+
*/
|
|
87
|
+
export function transformModuleWithAcorn(code) {
|
|
88
|
+
const ast = acorn.parse(code, {
|
|
89
|
+
sourceType: 'module',
|
|
90
|
+
ecmaVersion: 'latest',
|
|
91
|
+
locations: true,
|
|
92
|
+
onComment: [],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const getCode = node => code.slice(node.start, node.end);
|
|
96
|
+
const resolvedComponents = getResolvedComponents(code);
|
|
97
|
+
const isFileAComponent = code.includes('defineComponent'); // Detectar si el archivo es un componente Vue
|
|
98
|
+
const isVueInitializationFile =
|
|
99
|
+
code.includes('mount') || code.includes('createApp'); // Detectar si es un archivo de inicialización de Vue
|
|
100
|
+
|
|
101
|
+
// Heurística para isExternalImport (debe estar definida antes de usarse en isCoreDefinitionFile)
|
|
102
|
+
const isExternalImport = src => {
|
|
103
|
+
if (src.startsWith('vue') || src.startsWith('react')) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (!src.endsWith('.js')) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Nueva detección generalizada para archivos de definición central
|
|
113
|
+
let isCoreDefinitionFile = false;
|
|
114
|
+
try {
|
|
115
|
+
if (!isFileAComponent && !isVueInitializationFile) {
|
|
116
|
+
let importExportNodeCount = 0;
|
|
117
|
+
let hasLocalJsImport = false;
|
|
118
|
+
let totalTopLevelNodes = 0;
|
|
119
|
+
|
|
120
|
+
if (ast.body && ast.body.length > 0) {
|
|
121
|
+
totalTopLevelNodes = ast.body.length;
|
|
122
|
+
for (const node of ast.body) {
|
|
123
|
+
if (node.type === 'ImportDeclaration') {
|
|
124
|
+
importExportNodeCount++;
|
|
125
|
+
const sourceValue = node.source.value;
|
|
126
|
+
if (
|
|
127
|
+
sourceValue.endsWith('.js') &&
|
|
128
|
+
!isExternalImport(sourceValue)
|
|
129
|
+
) {
|
|
130
|
+
hasLocalJsImport = true;
|
|
131
|
+
}
|
|
132
|
+
} else if (
|
|
133
|
+
node.type === 'ExportNamedDeclaration' ||
|
|
134
|
+
node.type === 'ExportDefaultDeclaration'
|
|
135
|
+
) {
|
|
136
|
+
importExportNodeCount++;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (hasLocalJsImport && totalTopLevelNodes >= 2) {
|
|
141
|
+
// Mínimo 2 nodos para aplicar ratio
|
|
142
|
+
const ratio = importExportNodeCount / totalTopLevelNodes;
|
|
143
|
+
if (ratio >= 0.7) {
|
|
144
|
+
// Umbral ajustable (70%)
|
|
145
|
+
isCoreDefinitionFile = true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} catch (e) {
|
|
151
|
+
console.error(
|
|
152
|
+
'Error during isCoreDefinitionFile (ratio-based) check:',
|
|
153
|
+
e,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let nonDynamicImportStatements = [];
|
|
158
|
+
let hmrImports = { default: [], namespace: [], named: [] };
|
|
159
|
+
let importVarDecls = new Set();
|
|
160
|
+
|
|
161
|
+
// Primera pasada: clasificar imports
|
|
162
|
+
ast.body.forEach(node => {
|
|
163
|
+
if (node.type === 'ImportDeclaration') {
|
|
164
|
+
const sourceValue = node.source.value;
|
|
165
|
+
const importedLocalNames = node.specifiers.map(
|
|
166
|
+
spec => spec.local.name,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
let isResolvedCompImport = false;
|
|
170
|
+
for (const localName of importedLocalNames) {
|
|
171
|
+
if (resolvedComponents.has(localName)) {
|
|
172
|
+
isResolvedCompImport = true;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Condición actualizada para mantener el import estático
|
|
178
|
+
if (
|
|
179
|
+
isFileAComponent ||
|
|
180
|
+
isVueInitializationFile ||
|
|
181
|
+
isCoreDefinitionFile || // Usando la nueva heurística de ratio
|
|
182
|
+
isExternalImport(sourceValue) ||
|
|
183
|
+
isResolvedCompImport
|
|
184
|
+
) {
|
|
185
|
+
nonDynamicImportStatements.push(getCode(node));
|
|
186
|
+
} else {
|
|
187
|
+
// .js local, no es componente resuelto, y el archivo no cumple ninguna de las condiciones de exclusión -> transformar
|
|
188
|
+
node.specifiers.forEach(spec => {
|
|
189
|
+
const localName = spec.local.name;
|
|
190
|
+
importVarDecls.add(`let ${localName};`); // Declarar variable
|
|
191
|
+
|
|
192
|
+
if (spec.type === 'ImportDefaultSpecifier') {
|
|
193
|
+
hmrImports.default.push({
|
|
194
|
+
varName: localName,
|
|
195
|
+
filePath: sourceValue,
|
|
196
|
+
});
|
|
197
|
+
} else if (spec.type === 'ImportNamespaceSpecifier') {
|
|
198
|
+
hmrImports.namespace.push({
|
|
199
|
+
varName: localName,
|
|
200
|
+
filePath: sourceValue,
|
|
201
|
+
});
|
|
202
|
+
} else if (spec.type === 'ImportSpecifier') {
|
|
203
|
+
let namedEntry = hmrImports.named.find(
|
|
204
|
+
e => e.filePath === sourceValue,
|
|
205
|
+
);
|
|
206
|
+
if (!namedEntry) {
|
|
207
|
+
namedEntry = {
|
|
208
|
+
filePath: sourceValue,
|
|
209
|
+
namedExports: [],
|
|
210
|
+
variables: [],
|
|
211
|
+
};
|
|
212
|
+
hmrImports.named.push(namedEntry);
|
|
213
|
+
}
|
|
214
|
+
const exportString =
|
|
215
|
+
spec.imported.name === localName
|
|
216
|
+
? localName
|
|
217
|
+
: `${spec.imported.name} as ${localName}`;
|
|
218
|
+
if (!namedEntry.namedExports.includes(exportString)) {
|
|
219
|
+
namedEntry.namedExports.push(exportString);
|
|
220
|
+
}
|
|
221
|
+
if (!namedEntry.variables.includes(localName)) {
|
|
222
|
+
namedEntry.variables.push(localName);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Construir dynamicImportInitialLoadLines a partir de hmrImports consolidados
|
|
231
|
+
let dynamicImportInitialLoadLines = [];
|
|
232
|
+
hmrImports.default.forEach(imp => {
|
|
233
|
+
dynamicImportInitialLoadLines.push(
|
|
234
|
+
`${imp.varName} = (await import('${imp.filePath}')).default;`,
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
hmrImports.namespace.forEach(imp => {
|
|
238
|
+
dynamicImportInitialLoadLines.push(
|
|
239
|
+
`${imp.varName} = await import('${imp.filePath}');`,
|
|
240
|
+
);
|
|
241
|
+
});
|
|
242
|
+
hmrImports.named.forEach(imp => {
|
|
243
|
+
if (imp.namedExports.length > 0) {
|
|
244
|
+
dynamicImportInitialLoadLines.push(
|
|
245
|
+
`({ ${imp.namedExports.join(', ')} } = await import('${imp.filePath}'));`,
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
let exportStatements = [];
|
|
251
|
+
ast.body.forEach(node => {
|
|
252
|
+
if (
|
|
253
|
+
node.type === 'ExportNamedDeclaration' ||
|
|
254
|
+
node.type === 'ExportDefaultDeclaration'
|
|
255
|
+
) {
|
|
256
|
+
exportStatements.push(getCode(node));
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const bodyNodes = ast.body.filter(
|
|
261
|
+
n =>
|
|
262
|
+
n.type !== 'ImportDeclaration' &&
|
|
263
|
+
n.type !== 'ExportNamedDeclaration' &&
|
|
264
|
+
n.type !== 'ExportDefaultDeclaration',
|
|
265
|
+
);
|
|
266
|
+
const bodyNodesCode = bodyNodes.map(getCode).join('\n');
|
|
267
|
+
|
|
268
|
+
let result = nonDynamicImportStatements.join('\n');
|
|
269
|
+
if (importVarDecls.size > 0) {
|
|
270
|
+
result += '\n' + Array.from(importVarDecls).join('\n') + '\n';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const hasDynamicImports =
|
|
274
|
+
hmrImports.default.length > 0 ||
|
|
275
|
+
hmrImports.namespace.length > 0 ||
|
|
276
|
+
hmrImports.named.some(e => e.namedExports.length > 0);
|
|
277
|
+
|
|
278
|
+
if (hasDynamicImports) {
|
|
279
|
+
let hmrBlock = hasDynamicImports ? generateHMRBlock(hmrImports) : '';
|
|
280
|
+
const indentedHMRBlock = hmrBlock
|
|
281
|
+
.split('\n')
|
|
282
|
+
.map(line => ' ' + line)
|
|
283
|
+
.join('\n')
|
|
284
|
+
.trimStart();
|
|
285
|
+
|
|
286
|
+
// Indentar todo el bodyNodesCode si se mueve al IIFE
|
|
287
|
+
const indentedBodyNodesCode = bodyNodesCode
|
|
288
|
+
.split('\n')
|
|
289
|
+
.map(line => ' ' + line)
|
|
290
|
+
.join('\n')
|
|
291
|
+
.trimStart();
|
|
292
|
+
|
|
293
|
+
result += `\n(async () => {\n ${dynamicImportInitialLoadLines.join('\n ')}`;
|
|
294
|
+
if (indentedHMRBlock) result += `\n${indentedHMRBlock}`;
|
|
295
|
+
if (indentedBodyNodesCode) result += `\n ${indentedBodyNodesCode}`;
|
|
296
|
+
result += `\n})();\n`;
|
|
297
|
+
} else {
|
|
298
|
+
// Si no hay imports dinámicos, añadir bodyNodesCode directamente
|
|
299
|
+
result += '\n' + bodyNodesCode + '\n';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
result += '\n' + exportStatements.join('\n');
|
|
303
|
+
|
|
304
|
+
let finalOutput = result.trim(); // Limpiar espacios extra del ensamblaje
|
|
305
|
+
|
|
306
|
+
const shouldBeMarkedForReload =
|
|
307
|
+
isFileAComponent || isVueInitializationFile || isCoreDefinitionFile;
|
|
308
|
+
|
|
309
|
+
if (shouldBeMarkedForReload) {
|
|
310
|
+
// Asegurarse de no duplicar la marca
|
|
311
|
+
if (!finalOutput.startsWith('//versaHRM-reloadFILE')) {
|
|
312
|
+
finalOutput = '//versaHRM-reloadFILE\n' + finalOutput;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return finalOutput;
|
|
316
|
+
}
|
package/dist/utils/utils.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
/**
|
|
3
|
-
* Converts a 24-hour time string to a 12-hour time string with AM/PM.
|
|
4
|
-
*
|
|
5
|
-
* @param {number} timing - The value of the timing en miliseconds.
|
|
6
|
-
* @returns {string} the timing in ms, seconds, minutes or hours.
|
|
7
|
-
*/
|
|
8
|
-
export const showTimingForHumans = timing => {
|
|
9
|
-
if (timing < 1000) {
|
|
10
|
-
return `${timing} ms`;
|
|
11
|
-
} else if (timing < 60000) {
|
|
12
|
-
return `${timing / 1000} s`;
|
|
13
|
-
} else if (timing < 3600000) {
|
|
14
|
-
return `${timing / 60000} min`;
|
|
15
|
-
} else {
|
|
16
|
-
return `${timing / 3600000} h`;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Mapea una ruta de origen a una ruta de destino en el directorio de distribución.
|
|
22
|
-
* @param {string} ruta - La ruta de origen.
|
|
23
|
-
* @returns {Promise<string>} - La ruta mapeada en el directorio de distribución.
|
|
24
|
-
*/
|
|
25
|
-
export const mapRuta = async (ruta, PATH_DIST, PATH_SOURCE) =>
|
|
26
|
-
path.join(PATH_DIST, path.relative(PATH_SOURCE, ruta));
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Agrega la extensión .js a las importaciones en la cadena de datos proporcionada.
|
|
30
|
-
* @param {string} data - La cadena de entrada que contiene el código JavaScript.
|
|
31
|
-
* @returns {Promise<string>} - Una promesa que se resuelve con la cadena modificada con las importaciones actualizadas.
|
|
32
|
-
*/
|
|
33
|
-
export const addImportEndJs = async data => {
|
|
34
|
-
const importRegExp =
|
|
35
|
-
/(?:import\s+.*?from\s+['"](.*?)['"]|import\(['"](.*?)['"]\))/g; // Manejar importaciones estáticas y dinámicas
|
|
36
|
-
|
|
37
|
-
return data.replace(importRegExp, (match, ruta1, ruta2) => {
|
|
38
|
-
const ruta = ruta1 || ruta2; // Usar la ruta capturada, ya sea estática o dinámica
|
|
39
|
-
if (ruta.endsWith('.vue') || ruta.endsWith('.ts')) {
|
|
40
|
-
const fullPath = ruta.replace(/\.(vue|ts)$/, '.js');
|
|
41
|
-
return match.replace(ruta, fullPath);
|
|
42
|
-
} else if (!ruta.match(/\/.*\.(js|mjs|css)$/) && ruta.includes('/')) {
|
|
43
|
-
return match.replace(ruta, `${ruta}.js`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return match; // Devolver el match original si no se cumple ninguna condición
|
|
47
|
-
});
|
|
48
|
-
};
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a 24-hour time string to a 12-hour time string with AM/PM.
|
|
4
|
+
*
|
|
5
|
+
* @param {number} timing - The value of the timing en miliseconds.
|
|
6
|
+
* @returns {string} the timing in ms, seconds, minutes or hours.
|
|
7
|
+
*/
|
|
8
|
+
export const showTimingForHumans = timing => {
|
|
9
|
+
if (timing < 1000) {
|
|
10
|
+
return `${timing} ms`;
|
|
11
|
+
} else if (timing < 60000) {
|
|
12
|
+
return `${timing / 1000} s`;
|
|
13
|
+
} else if (timing < 3600000) {
|
|
14
|
+
return `${timing / 60000} min`;
|
|
15
|
+
} else {
|
|
16
|
+
return `${timing / 3600000} h`;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Mapea una ruta de origen a una ruta de destino en el directorio de distribución.
|
|
22
|
+
* @param {string} ruta - La ruta de origen.
|
|
23
|
+
* @returns {Promise<string>} - La ruta mapeada en el directorio de distribución.
|
|
24
|
+
*/
|
|
25
|
+
export const mapRuta = async (ruta, PATH_DIST, PATH_SOURCE) =>
|
|
26
|
+
path.join(PATH_DIST, path.relative(PATH_SOURCE, ruta));
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Agrega la extensión .js a las importaciones en la cadena de datos proporcionada.
|
|
30
|
+
* @param {string} data - La cadena de entrada que contiene el código JavaScript.
|
|
31
|
+
* @returns {Promise<string>} - Una promesa que se resuelve con la cadena modificada con las importaciones actualizadas.
|
|
32
|
+
*/
|
|
33
|
+
export const addImportEndJs = async data => {
|
|
34
|
+
const importRegExp =
|
|
35
|
+
/(?:import\s+.*?from\s+['"](.*?)['"]|import\(['"](.*?)['"]\))/g; // Manejar importaciones estáticas y dinámicas
|
|
36
|
+
|
|
37
|
+
return data.replace(importRegExp, (match, ruta1, ruta2) => {
|
|
38
|
+
const ruta = ruta1 || ruta2; // Usar la ruta capturada, ya sea estática o dinámica
|
|
39
|
+
if (ruta.endsWith('.vue') || ruta.endsWith('.ts')) {
|
|
40
|
+
const fullPath = ruta.replace(/\.(vue|ts)$/, '.js');
|
|
41
|
+
return match.replace(ruta, fullPath);
|
|
42
|
+
} else if (!ruta.match(/\/.*\.(js|mjs|css)$/) && ruta.includes('/')) {
|
|
43
|
+
return match.replace(ruta, `${ruta}.js`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return match; // Devolver el match original si no se cumple ninguna condición
|
|
47
|
+
});
|
|
48
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "versacompiler",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Una herramienta para compilar y minificar archivos .vue, .js y .ts para proyectos de Vue 3 con soporte para TypeScript.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"dev": "node --watch dist/index.js",
|
|
20
20
|
"compile": "node dist/index.js",
|
|
21
21
|
"compile-dev": "node dist/index.js --all",
|
|
22
|
-
"compile-prod": "node dist/index.js --all --prod"
|
|
22
|
+
"compile-prod": "node dist/index.js --all --prod",
|
|
23
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
|
|
23
24
|
},
|
|
24
25
|
"keywords": [
|
|
25
26
|
"vue",
|
|
@@ -37,9 +38,9 @@
|
|
|
37
38
|
"chalk": "5.4.1",
|
|
38
39
|
"chokidar": "^4.0.3",
|
|
39
40
|
"get-port": "^7.1.0",
|
|
40
|
-
"oxc-minify": "^0.
|
|
41
|
+
"oxc-minify": "^0.70.0",
|
|
41
42
|
"typescript": "^5.8.3",
|
|
42
|
-
"vue": "3.5.
|
|
43
|
+
"vue": "3.5.14"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@tailwindcss/cli": "^4.1.6",
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
"code-tag": "^1.2.0",
|
|
48
49
|
"oxlint": "^0.16.10",
|
|
49
50
|
"prettier": "3.5.3",
|
|
50
|
-
"tailwindcss": "^4.1.6"
|
|
51
|
+
"tailwindcss": "^4.1.6",
|
|
52
|
+
"jest": "^29.7.0"
|
|
51
53
|
}
|
|
52
54
|
}
|