versacompiler 2.5.0 → 2.6.1

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.
Files changed (50) hide show
  1. package/README.md +70 -54
  2. package/dist/compiler/compile-worker-pool.js +12 -0
  3. package/dist/compiler/compile.js +102 -17
  4. package/dist/compiler/error-reporter.js +12 -0
  5. package/dist/compiler/integrity-validator.js +12 -0
  6. package/dist/compiler/linter.js +12 -0
  7. package/dist/compiler/minify.js +12 -0
  8. package/dist/compiler/minifyTemplate.js +12 -0
  9. package/dist/compiler/module-resolution-optimizer.js +13 -1
  10. package/dist/compiler/parser.js +12 -0
  11. package/dist/compiler/performance-monitor.js +12 -0
  12. package/dist/compiler/pipeline/build-pipeline.js +12 -0
  13. package/dist/compiler/pipeline/core-plugins.js +12 -0
  14. package/dist/compiler/pipeline/module-graph.js +12 -0
  15. package/dist/compiler/pipeline/plugin-driver.js +12 -0
  16. package/dist/compiler/pipeline/types.js +12 -0
  17. package/dist/compiler/tailwindcss.js +12 -0
  18. package/dist/compiler/transform-optimizer.js +12 -0
  19. package/dist/compiler/transformTStoJS.js +38 -5
  20. package/dist/compiler/transforms.js +12 -0
  21. package/dist/compiler/typescript-compiler.js +12 -0
  22. package/dist/compiler/typescript-error-parser.js +12 -0
  23. package/dist/compiler/typescript-manager.js +12 -0
  24. package/dist/compiler/typescript-sync-validator.js +12 -0
  25. package/dist/compiler/typescript-worker-pool.js +12 -0
  26. package/dist/compiler/typescript-worker.js +12 -0
  27. package/dist/compiler/vuejs.js +41 -15
  28. package/dist/config.js +12 -0
  29. package/dist/hrm/VueHRM.js +132 -7
  30. package/dist/hrm/errorScreen.js +12 -0
  31. package/dist/hrm/getInstanciaVue.js +12 -0
  32. package/dist/hrm/initHRM.js +117 -9
  33. package/dist/hrm/versaHMR.js +317 -0
  34. package/dist/main.js +9 -2
  35. package/dist/servicios/browserSync.js +119 -4
  36. package/dist/servicios/file-watcher.js +104 -15
  37. package/dist/servicios/logger.js +12 -0
  38. package/dist/servicios/readConfig.js +13 -1
  39. package/dist/servicios/versacompile.config.types.js +12 -0
  40. package/dist/utils/excluded-modules.js +12 -0
  41. package/dist/utils/module-resolver.js +12 -0
  42. package/dist/utils/promptUser.js +12 -0
  43. package/dist/utils/proxyValidator.js +12 -0
  44. package/dist/utils/resolve-bin.js +12 -0
  45. package/dist/utils/utils.js +12 -0
  46. package/dist/utils/vue-types-setup.js +14 -2
  47. package/dist/wrappers/eslint-node.js +12 -0
  48. package/dist/wrappers/oxlint-node.js +12 -0
  49. package/dist/wrappers/tailwind-node.js +12 -0
  50. package/package.json +4 -3
@@ -1,16 +1,49 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  import { transform } from '/node_modules/oxc-transform/browser.js';
2
- export async function traspileTStoJS(filePath, sourceCode) {
14
+ export async function transpileTStoJS(filePath, sourceCode) {
3
15
  try {
4
16
  const { code: outputText, declaration, errors: diagnostics, } = await transform(filePath, sourceCode);
17
+ // Si oxc-transform devuelve código vacío ante una entrada no vacía,
18
+ // usar el fuente original como fallback para no corromper el pipeline.
19
+ if (!outputText && sourceCode.trim()) {
20
+ return {
21
+ outputText: sourceCode,
22
+ declaration: declaration || '',
23
+ diagnostics: [
24
+ `Warning: oxc-transform produjo salida vacía para ${filePath}, usando fuente original`,
25
+ ...(diagnostics ?? []).map(d => typeof d === 'string' ? d : JSON.stringify(d)),
26
+ ],
27
+ };
28
+ }
5
29
  return {
6
- outputText: outputText,
30
+ outputText: outputText ?? sourceCode,
7
31
  declaration: declaration || '',
8
- diagnostics: diagnostics || [],
32
+ diagnostics: (diagnostics ?? []).map(d => typeof d === 'string' ? d : JSON.stringify(d)),
9
33
  };
10
34
  }
11
35
  catch (error) {
12
- console.error(`Error transpiling ${filePath}:`, error);
13
- return { outputText: '', declaration: '', diagnostics: [error] };
36
+ const errorMsg = error instanceof Error ? error.message : String(error);
37
+ // Fallback al fuente original para que el pipeline no reciba código vacío
38
+ return {
39
+ outputText: sourceCode,
40
+ declaration: '',
41
+ diagnostics: [
42
+ `Error durante transpilación de ${filePath}: ${errorMsg}. Usando fuente original.`,
43
+ ],
44
+ };
14
45
  }
15
46
  }
47
+ /** @deprecated Usar transpileTStoJS (corrección de typo histórico) */
48
+ export const traspileTStoJS = transpileTStoJS;
16
49
  //# sourceMappingURL=transformTStoJS.js.map
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  import path from 'node:path';
2
14
  import { env } from 'node:process';
3
15
  import { logger } from '../servicios/logger.js';
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  import fs from 'node:fs';
2
14
  import path from 'node:path';
3
15
  import * as process from 'node:process';
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  import { readFileSync } from 'node:fs';
2
14
  import * as typescript from 'typescript';
3
15
  /**
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  import fs from 'node:fs';
2
14
  import path from 'node:path';
3
15
  import * as process from 'node:process';
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  /**
2
14
  * TypeScript Sync Validator - Validación síncrona de tipos como fallback
3
15
  * Contiene la lógica extraída del módulo principal para cuando el worker no está disponible
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  /**
2
14
  * TypeScript Worker Pool - Pool de workers para compilación paralela
3
15
  * Reemplaza el worker único con múltiples workers para aprovecha la concurrencia real
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  /**
2
14
  * TypeScript Worker Manager - Gestiona workers dedicados para type checking asíncrono
3
15
  * Implementa el patrón Singleton para reutilizar workers entre compilaciones
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  import { createHash } from 'node:crypto';
2
14
  import path from 'node:path';
3
15
  import * as vCompiler from 'vue/compiler-sfc';
@@ -63,19 +75,30 @@ class VueHMRInjectionCache {
63
75
  else {
64
76
  injectedData = originalData.replace(/(<script.*?>)/, `$1${varContent}`);
65
77
  }
66
- // Inyectar :key en el template
67
- injectedData = injectedData.replace(/(<template[^>]*>[\s\S]*?)(<(\w+)([^>]*?))(\/?>)/, (match, p1, p2, p3, p4, p5) => {
68
- if (p4.includes(':key=') || p4.includes('key=')) {
69
- return match;
70
- }
71
- const isSelfClosing = p5 === '/>';
72
- if (isSelfClosing) {
73
- return `${p1}<${p3}${p4} :key="versaComponentKey" />`;
74
- }
75
- else {
76
- return `${p1}<${p3}${p4} :key="versaComponentKey">`;
78
+ // Inyectar :key en el primer elemento hijo del template.
79
+ // Dos pasos para evitar backtracking catastrófico (ReDoS) que ocurría con
80
+ // el pattern combinado /(<template[^>]*>[\s\S]*?)(<(\w+)([^>]*?))(\/?>)/
81
+ const templateTagMatch = /(<template[^>]*>)/.exec(injectedData);
82
+ if (templateTagMatch) {
83
+ const templateEnd = templateTagMatch.index + templateTagMatch[0].length;
84
+ const afterTemplate = injectedData.slice(templateEnd);
85
+ // Buscar el primer tag de elemento (ignora espacios/comentarios) justo después del <template>
86
+ const firstChildMatch = /^(\s*)(<(\w+)([^>]*?)(\/?>))/.exec(afterTemplate);
87
+ if (firstChildMatch) {
88
+ const [, whitespace = '', fullTag = '', tagName, attrs = '', closing,] = firstChildMatch;
89
+ if (!attrs.includes(':key=') && !attrs.includes('key=')) {
90
+ const isSelfClosing = closing === '/>';
91
+ const newTag = isSelfClosing
92
+ ? `<${tagName}${attrs} :key="versaComponentKey" />`
93
+ : `<${tagName}${attrs} :key="versaComponentKey">`;
94
+ injectedData =
95
+ injectedData.slice(0, templateEnd) +
96
+ whitespace +
97
+ newTag +
98
+ afterTemplate.slice(whitespace.length + fullTag.length);
99
+ }
77
100
  }
78
- });
101
+ }
79
102
  // Cachear resultado
80
103
  this.cache.set(cacheKey, {
81
104
  contentHash,
@@ -167,8 +190,6 @@ export const preCompileVue = async (data, source, isProd = false) => {
167
190
  scriptInfo: undefined,
168
191
  };
169
192
  }
170
- // Guardar el código original antes de inyectar HMR
171
- const originalData = data;
172
193
  if (!isProd) {
173
194
  const { injectedData } = hmrInjectionCache.getOrGenerateHMRInjection(data, fileName);
174
195
  data = injectedData;
@@ -312,10 +333,14 @@ export const preCompileVue = async (data, source, isProd = false) => {
312
333
  filename: `${fileName}.vue`,
313
334
  });
314
335
  });
336
+ // data-versa-hmr-component permite a VueHRM.js eliminar style tags
337
+ // de ciclos HMR anteriores para evitar acumulación de estilos duplicados.
338
+ const sanitizedForAttr = fileName.replace(/[^a-zA-Z0-9_-]/g, '');
315
339
  const insertStyles = compiledStyles.length
316
340
  ? `(function(){
317
341
  let styleTag = document.createElement('style');
318
342
  styleTag.setAttribute('data-v-${id}', '');
343
+ styleTag.setAttribute('data-versa-hmr-component', '${sanitizedForAttr}');
319
344
  styleTag.innerHTML = \`${compiledStyles.map((s) => s.code).join('\n')}\`;
320
345
  document.head.appendChild(styleTag);
321
346
  })();`
@@ -380,6 +405,8 @@ export const preCompileVue = async (data, source, isProd = false) => {
380
405
  export default ${componentName}; `;
381
406
  output = `${output}\n${finishComponent}`;
382
407
  // 🚀 OPTIMIZACIÓN CRÍTICA: Evitar crear scriptInfo si no hay script
408
+ // originalData NO se incluye en scriptInfo para evitar retener la cadena completa
409
+ // del .vue en memoria. Se pasa por separado como sourceCode en parseTypeScriptErrors.
383
410
  const result = {
384
411
  lang: finalCompiledScript.lang,
385
412
  error: null,
@@ -391,7 +418,6 @@ export const preCompileVue = async (data, source, isProd = false) => {
391
418
  startLine: (descriptor.script || descriptor.scriptSetup).loc?.start
392
419
  .line || 1,
393
420
  content: (descriptor.script || descriptor.scriptSetup).content,
394
- originalData: originalData, // String directa, no closure
395
421
  };
396
422
  }
397
423
  return result;
package/dist/config.js CHANGED
@@ -1,2 +1,14 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  export { defineConfig, } from './servicios/versacompile.config.types';
2
14
  //# sourceMappingURL=config.js.map
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  /**
2
14
  * @typedef {Object} TreeNode
3
15
  * @property {string} name - Nombre del componente
@@ -222,7 +234,80 @@ function tryForceUpdate(instance) {
222
234
  }
223
235
 
224
236
  /**
225
- * Intenta actualizar un componente en el camino del árbol
237
+ * Limpia los caches internos de Vue para una definición de componente.
238
+ * Necesario para que Vue detecte el cambio de props/emits/options.
239
+ * @param {Object} appContext - Contexto de la app Vue (instance.appContext)
240
+ * @param {Object} componentDef - Definición del componente
241
+ */
242
+ function clearVueCaches(appContext, componentDef) {
243
+ if (!appContext || !componentDef) return;
244
+ try {
245
+ appContext.propsCache?.delete(componentDef);
246
+ appContext.emitsCache?.delete(componentDef);
247
+ appContext.optionsCache?.delete(componentDef);
248
+ } catch {
249
+ // Los caches pueden no existir en todas las versiones de Vue
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Actualiza una instancia de componente Vue en-place con la nueva definición.
255
+ * Muta el objeto `instance.type` directamente para que TODAS las referencias
256
+ * a la definición (incluidas las capturadas en closures de render functions
257
+ * de componentes padre que hacen import estático) vean la nueva versión.
258
+ *
259
+ * @param {Object} instance - Instancia Vue del componente a actualizar
260
+ * @param {Object} newComponentDef - Nueva definición del componente
261
+ * @returns {boolean} true si la actualización fue exitosa
262
+ */
263
+ function updateInstanceInPlace(instance, newComponentDef) {
264
+ if (!instance || !newComponentDef) return false;
265
+
266
+ const oldDef = instance.type;
267
+ if (!oldDef || typeof oldDef !== 'object') return false;
268
+
269
+ // 1. Mutar la definición existente en-place.
270
+ // Object.assign copia propiedades enumerables; copiamos render/setup
271
+ // explícitamente porque pueden no ser enumerables en algunos builds.
272
+ Object.assign(oldDef, newComponentDef);
273
+ if (newComponentDef.render) oldDef.render = newComponentDef.render;
274
+ if (newComponentDef.setup) oldDef.setup = newComponentDef.setup;
275
+ if (newComponentDef.ssrRender) oldDef.ssrRender = newComponentDef.ssrRender;
276
+
277
+ // 2. Actualizar instance.render directamente.
278
+ // Vue almacena la referencia a la render function en instance.render durante
279
+ // el mount (handleSetupResult), y es ESA la que llama en cada patch.
280
+ // Cambiar solo instance.type.render NO es suficiente — hay que actualizar
281
+ // también instance.render para que el próximo update use la nueva template.
282
+ if (newComponentDef.render && typeof instance.render !== 'undefined') {
283
+ instance.render = newComponentDef.render;
284
+ }
285
+
286
+ // 3. Limpiar caches internos de Vue para que re-evalúe props/emits/options.
287
+ clearVueCaches(instance.appContext, oldDef);
288
+
289
+ // 4. Forzar actualización de ESTA instancia directamente (no solo del padre).
290
+ // Incrementar versaComponentKey para triggear el :key del template.
291
+ if (instance.ctx?._.setupState?.versaComponentKey !== undefined) {
292
+ instance.ctx._.setupState.versaComponentKey++;
293
+ }
294
+ if (typeof instance.update === 'function') {
295
+ instance.update();
296
+ return true;
297
+ }
298
+ if (instance.proxy && typeof instance.proxy.$forceUpdate === 'function') {
299
+ instance.proxy.$forceUpdate();
300
+ return true;
301
+ }
302
+
303
+ return false;
304
+ }
305
+
306
+ /**
307
+ * Intenta actualizar un componente en el camino del árbol.
308
+ * Ahora usa mutación in-place de la definición + limpieza de caches Vue,
309
+ * en lugar de reemplazar la referencia en el mapa de components del padre.
310
+ *
226
311
  * @param {TreeNode[]} path - Camino de nodos desde el componente hasta la raíz
227
312
  * @param {Object} newComponent - Nuevo componente a usar
228
313
  * @param {string} componentName - Nombre del componente
@@ -235,7 +320,25 @@ function tryUpdateComponentPath(path, newComponent, componentName, App) {
235
320
  return false;
236
321
  }
237
322
 
238
- // Recorrer el path desde el padre hacia la raíz (saltando el primer elemento que es el propio componente)
323
+ // path[0] es el nodo del propio componente a actualizar.
324
+ // Intentar actualización directa en la instancia del componente.
325
+ const targetNode = path[0];
326
+ if (targetNode?.instancia) {
327
+ const updated = updateInstanceInPlace(
328
+ targetNode.instancia,
329
+ newComponent,
330
+ );
331
+ if (updated) {
332
+ // También forzar actualización del padre para que el vdom se reconcilie.
333
+ const parentNode = path[1];
334
+ if (parentNode?.instancia && !parentNode.isRoot) {
335
+ tryForceUpdate(parentNode.instancia);
336
+ }
337
+ return true;
338
+ }
339
+ }
340
+
341
+ // Fallback: recorrer hacia el padre si el nodo propio no es accesible.
239
342
  for (let i = 1; i < path.length; i++) {
240
343
  const parent = path[i];
241
344
 
@@ -244,19 +347,29 @@ function tryUpdateComponentPath(path, newComponent, componentName, App) {
244
347
  return true;
245
348
  }
246
349
 
247
- if (!parent || !parent.instancia) {
350
+ if (!parent?.instancia) {
248
351
  console.error('❌ Nodo padre no válido en el camino:', parent);
249
- continue; // Continúa con el siguiente padre en lugar de fallar
352
+ continue;
250
353
  }
251
354
 
252
- // Actualizar la instancia del componente
253
355
  const componentsDefinition =
254
356
  parent.instancia?.type?.components || parent.instancia?.components;
255
357
 
256
358
  if (componentsDefinition && componentsDefinition[componentName]) {
257
- componentsDefinition[componentName] = newComponent;
359
+ // Mutar la definición existente en el mapa del padre también,
360
+ // para que nuevas instancias del componente creadas después se usen
361
+ // con la definición actualizada.
362
+ const existingDef = componentsDefinition[componentName];
363
+ if (existingDef && typeof existingDef === 'object') {
364
+ Object.assign(existingDef, newComponent);
365
+ if (newComponent.render)
366
+ existingDef.render = newComponent.render;
367
+ if (newComponent.setup) existingDef.setup = newComponent.setup;
368
+ clearVueCaches(parent.instancia.appContext, existingDef);
369
+ } else {
370
+ componentsDefinition[componentName] = newComponent;
371
+ }
258
372
 
259
- // Forzar actualización de la instancia padre
260
373
  return (
261
374
  tryForceUpdate(parent.instancia) ||
262
375
  tryForceUpdate(parent.instancia.proxy)
@@ -297,6 +410,18 @@ export async function reloadComponent(App, Component) {
297
410
  const timestamp = Date.now();
298
411
  const moduleUrl = `${urlOrigin}?t=${timestamp}`;
299
412
 
413
+ // Eliminar style tags del ciclo HMR anterior para este componente
414
+ // para evitar acumulación de estilos duplicados en el documento.
415
+ const componentName_clean = componentName.replace(
416
+ /[^a-zA-Z0-9_-]/g,
417
+ '',
418
+ );
419
+ document
420
+ .querySelectorAll(
421
+ `[data-versa-hmr-component="${componentName_clean}"]`,
422
+ )
423
+ .forEach(el => el.remove());
424
+
300
425
  const module = await import(moduleUrl);
301
426
 
302
427
  if (!module.default) {
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  /**
2
14
  * Variable global que mantiene la referencia al overlay de error actual
3
15
  * @type {HTMLElement|null}
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  /**
2
14
  * Script para obtener la instancia de Vue usando solo JavaScript
3
15
  * Compatible con Vue 2 y Vue 3