versacompiler 1.0.3 → 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.
@@ -0,0 +1,346 @@
1
+ let currentComponentTree = null;
2
+
3
+ function findNodeByInstance(tree, instance) {
4
+ if (tree.name === instance) return tree;
5
+ for (const child of tree.children) {
6
+ const found = findNodeByInstance(child, instance);
7
+ if (found) return found;
8
+ }
9
+ return null;
10
+ }
11
+
12
+ function getPathToRoot(node) {
13
+ const path = [];
14
+ while (node) {
15
+ path.push(node);
16
+ node = node.parent;
17
+ }
18
+ return path; // Ordenado desde hijo hasta raíz
19
+ }
20
+
21
+ // Función auxiliar para encontrar componentes recursivamente dentro de un VNode genérico
22
+ function recursivelyFindComponentsInVNode(vnode, parentTreeNode) {
23
+ if (!vnode || typeof vnode !== 'object') {
24
+ return;
25
+ }
26
+
27
+ if (vnode.component) {
28
+ const childComponentInstance = vnode.component;
29
+
30
+ let componentName = 'Anonymous';
31
+ if (childComponentInstance.type) {
32
+ if (childComponentInstance.type.name) {
33
+ componentName = childComponentInstance.type.name;
34
+ } else if (childComponentInstance.type.__name) {
35
+ componentName = childComponentInstance.type.__name;
36
+ } else if (typeof childComponentInstance.type === 'function') {
37
+ const funcName = childComponentInstance.type.name;
38
+ if (funcName && funcName !== 'Anonymous function') {
39
+ componentName = funcName;
40
+ }
41
+ // Heurísticas para componentes comunes de Vue
42
+ const typeStr = childComponentInstance.type.toString();
43
+ if (typeStr.includes('BaseTransition')) {
44
+ componentName = 'Transition';
45
+ } else if (typeStr.includes('KeepAlive')) {
46
+ componentName = 'KeepAlive';
47
+ } else if (typeStr.includes('Suspense')) {
48
+ componentName = 'Suspense';
49
+ }
50
+ }
51
+ }
52
+
53
+ const childTreeNode = {
54
+ name: componentName,
55
+ instancia: childComponentInstance,
56
+ children: [],
57
+ parent: parentTreeNode,
58
+ isRoot: false,
59
+ };
60
+ parentTreeNode.children.push(childTreeNode);
61
+ traverseComponentInstance(childComponentInstance, childTreeNode);
62
+ } else {
63
+ const childrenToExplore = vnode.children || vnode.dynamicChildren;
64
+ if (Array.isArray(childrenToExplore)) {
65
+ childrenToExplore.forEach(childVNode => {
66
+ recursivelyFindComponentsInVNode(childVNode, parentTreeNode);
67
+ });
68
+ }
69
+ }
70
+ }
71
+
72
+ // Función principal de recorrido, ahora llamada traverseComponentInstance
73
+ function traverseComponentInstance(componentInstance, currentTreeNode) {
74
+ const subTreeVNode = componentInstance.subTree;
75
+
76
+ if (!subTreeVNode) {
77
+ return;
78
+ }
79
+
80
+ recursivelyFindComponentsInVNode(subTreeVNode, currentTreeNode);
81
+ }
82
+
83
+ export const buildComponentTree = componentRootInstance => {
84
+ const tree = {
85
+ name:
86
+ componentRootInstance.type?.name ||
87
+ componentRootInstance.type?.__name ||
88
+ 'Anonymous',
89
+ instancia: componentRootInstance,
90
+ children: [],
91
+ parent: null,
92
+ isRoot: true,
93
+ };
94
+ traverseComponentInstance(componentRootInstance, tree);
95
+ return tree;
96
+ };
97
+
98
+ // Nueva función auxiliar para intentar forzar la actualización de una instancia
99
+ function tryForceUpdate(instance) {
100
+ if (!instance) {
101
+ return false;
102
+ }
103
+ if (instance.proxy && typeof instance.proxy.$forceUpdate === 'function') {
104
+ instance.proxy.$forceUpdate();
105
+ instance.update();
106
+ // buscar una varible en el componente que se llame versaComponentKey y sumarle 1
107
+ instance.ctx._.setupState.versaComponentKey++;
108
+ return true;
109
+ }
110
+ if (typeof instance.update === 'function') {
111
+ if (instance.ctx._.setupState.versaComponentKey) {
112
+ instance.ctx._.setupState.versaComponentKey++;
113
+ }
114
+ instance.update();
115
+ return true;
116
+ }
117
+ return false;
118
+ }
119
+
120
+ export async function reloadComponent(
121
+ app,
122
+ componentName,
123
+ relativePath,
124
+ _extension,
125
+ _type,
126
+ ) {
127
+ try {
128
+ const baseUrl = window.location.href;
129
+ // console.log(relativePath);
130
+ const newBaseUrl = new URL(baseUrl);
131
+ const urlOrigin = `${newBaseUrl.origin}/${relativePath}`;
132
+ const module = await import(`${urlOrigin}?t=${Date.now()}`);
133
+ currentComponentTree = buildComponentTree(app._instance);
134
+
135
+ const targetNode = findNodeByInstance(
136
+ currentComponentTree,
137
+ componentName,
138
+ );
139
+ const path = getPathToRoot(targetNode);
140
+ for (const instanciaParent of path) {
141
+ if (
142
+ instanciaParent.isRoot ||
143
+ instanciaParent.name === 'KeepAlive'
144
+ ) {
145
+ window.location.reload();
146
+ return;
147
+ }
148
+ if (instanciaParent.name !== componentName) {
149
+ if (
150
+ instanciaParent.name !== 'BaseTransition' &&
151
+ instanciaParent.name !== 'Transition' &&
152
+ instanciaParent.name !== 'Suspense'
153
+ ) {
154
+ const componentsDefinition =
155
+ instanciaParent.instancia?.type?.components ||
156
+ instanciaParent.instancia?.components;
157
+
158
+ if (
159
+ componentsDefinition &&
160
+ componentsDefinition[componentName]
161
+ ) {
162
+ componentsDefinition[componentName] = module.default;
163
+ if (tryForceUpdate(instanciaParent.instancia)) {
164
+ console.log(
165
+ `✔️ Versa HMR: Component updated successfully`,
166
+ );
167
+ return;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ return null;
174
+ } catch (error) {
175
+ console.log(error.stack);
176
+ return {
177
+ msg: `Error al recargar ${componentName}: ${error}`,
178
+ error,
179
+ };
180
+ }
181
+ }
182
+
183
+ // Función Debounce
184
+ export function debounce(func, waitFor) {
185
+ let timeout = null;
186
+
187
+ const debounced = (...args) => {
188
+ if (timeout) {
189
+ clearTimeout(timeout);
190
+ }
191
+ timeout = setTimeout(() => func(...args), waitFor);
192
+ };
193
+
194
+ return debounced;
195
+ }
196
+
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
+ }
295
+ }
296
+
297
+ export function socketReload(app) {
298
+ if (window.___browserSync___?.socket) {
299
+ // const socket = window.___browserSync___.socket;
300
+ // Configura el observer para actualizar el árbol de componentes en cada mutación relevante
301
+ if (app && app._container) {
302
+ currentComponentTree = buildComponentTree(app._instance);
303
+ initializeMutationObserver(app._container, () => {
304
+ if (app._instance) {
305
+ currentComponentTree = buildComponentTree(app._instance);
306
+ }
307
+ });
308
+ }
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
+ // }
315
+
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
+ // });
330
+ } else {
331
+ setTimeout(() => {
332
+ window.location.reload();
333
+ }, 5000);
334
+ }
335
+ }
336
+
337
+ function initializeMutationObserver(targetNode, callback, options) {
338
+ const observerInstance = new MutationObserver(callback);
339
+ const defaultOptions = {
340
+ childList: true,
341
+ subtree: true,
342
+ attributes: false,
343
+ };
344
+ observerInstance.observe(targetNode, { ...defaultOptions, ...options });
345
+ return observerInstance;
346
+ }
@@ -0,0 +1,61 @@
1
+ let errorOverlay;
2
+ export function hideErrorOverlay() {
3
+ const existingOverlay = document.getElementById('versa-hmr-error-overlay');
4
+ if (existingOverlay) {
5
+ existingOverlay.remove();
6
+ }
7
+ errorOverlay = null;
8
+ }
9
+ export function showErrorOverlay(errorMessage, errorDetails = '') {
10
+ hideErrorOverlay(); // Ensure no duplicate overlays
11
+
12
+ errorOverlay = document.createElement('div');
13
+ errorOverlay.id = 'versa-hmr-error-overlay';
14
+ errorOverlay.style.position = 'fixed';
15
+ errorOverlay.style.top = '0';
16
+ errorOverlay.style.left = '0';
17
+ errorOverlay.style.width = '100vw';
18
+ errorOverlay.style.height = '100vh';
19
+ errorOverlay.style.backgroundColor = 'rgba(0, 0, 0, 1.85)';
20
+ errorOverlay.style.color = '#ff8080';
21
+ errorOverlay.style.zIndex = '999999';
22
+ errorOverlay.style.display = 'flex';
23
+ errorOverlay.style.flexDirection = 'column';
24
+ errorOverlay.style.alignItems = 'center';
25
+ errorOverlay.style.justifyContent = 'center';
26
+ errorOverlay.style.fontFamily = 'monospace';
27
+ errorOverlay.style.fontSize = '16px';
28
+ errorOverlay.style.padding = '20px';
29
+ errorOverlay.style.boxSizing = 'border-box';
30
+ errorOverlay.style.textAlign = 'left';
31
+ errorOverlay.style.overflow = 'auto';
32
+
33
+ const title = document.createElement('h2');
34
+ title.textContent = 'Versa HMR Error';
35
+ title.style.color = '#ff4d4d';
36
+ title.style.fontSize = '24px';
37
+ title.style.marginBottom = '20px';
38
+
39
+ const messageDiv = document.createElement('div');
40
+ messageDiv.textContent = errorMessage;
41
+ messageDiv.style.marginBottom = '15px';
42
+ messageDiv.style.whiteSpace = 'pre-wrap';
43
+
44
+ const detailsPre = document.createElement('pre');
45
+ detailsPre.textContent = errorDetails;
46
+ detailsPre.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
47
+ detailsPre.style.padding = '10px';
48
+ detailsPre.style.borderRadius = '5px';
49
+ detailsPre.style.maxHeight = '50vh';
50
+ detailsPre.style.overflow = 'auto';
51
+ detailsPre.style.width = '100%';
52
+ detailsPre.style.maxWidth = '800px';
53
+
54
+ errorOverlay.appendChild(title);
55
+ errorOverlay.appendChild(messageDiv);
56
+ if (errorDetails) {
57
+ errorOverlay.appendChild(detailsPre);
58
+ }
59
+
60
+ document.body.appendChild(errorOverlay);
61
+ }
@@ -0,0 +1,35 @@
1
+ // Store for the Vue app instance
2
+ let vueAppInstance = null;
3
+
4
+ // Exponer la instancia en window para acceso global
5
+ if (typeof window !== 'undefined') {
6
+ window.__VUE_APP_INSTANCE__ = {
7
+ set: function(instance) {
8
+ vueAppInstance = instance;
9
+ console.log('Vue app instance stored successfully in window.__VUE_APP_INSTANCE__');
10
+ return instance;
11
+ },
12
+ get: function() {
13
+ return vueAppInstance;
14
+ }
15
+ };
16
+ }
17
+
18
+ export default {
19
+ methods: {
20
+ // Set the Vue app instance
21
+ set(instance) {
22
+ vueAppInstance = instance;
23
+ // También lo guardamos en window para acceso global
24
+ if (typeof window !== 'undefined') {
25
+ window.__VUE_APP_INSTANCE__.set(instance);
26
+ }
27
+ console.log('Vue app instance stored successfully');
28
+ return instance;
29
+ },
30
+ // Get the Vue app instance
31
+ get() {
32
+ return vueAppInstance;
33
+ },
34
+ },
35
+ };
@@ -0,0 +1,57 @@
1
+ // setupHMR.js - Helper to set up Hot Module Reloading for Vue
2
+ import instanciaVue from './instanciaVue.js';
3
+
4
+ /**
5
+ * Set up Hot Module Reloading for a Vue application
6
+ * @param {Object} app - The Vue application instance
7
+ * @returns {Object} - The same Vue application instance
8
+ */
9
+ export function setupHMR(app) {
10
+ // Store the Vue app instance in our instanciaVue module
11
+ instanciaVue.methods.set(app);
12
+
13
+ // También lo guardamos directamente en window para mayor accesibilidad
14
+ if (typeof window !== 'undefined') {
15
+ window.__VUE_APP__ = app;
16
+ console.log('Vue app instance stored directly in window.__VUE_APP__');
17
+ }
18
+
19
+ console.log('HMR setup complete - Vue instance stored for hot reloading');
20
+
21
+ return app;
22
+ }
23
+
24
+ /**
25
+ * Helper function to wrap your Vue app creation with HMR support
26
+ * @param {Function} createAppFn - Function that creates and returns your Vue app
27
+ * @returns {Object} - The Vue application instance with HMR support
28
+ */
29
+ export function createAppWithHMR(createAppFn) {
30
+ const app = createAppFn();
31
+ return setupHMR(app);
32
+ }
33
+
34
+ /**
35
+ * Función para obtener la instancia de Vue desde cualquier parte de la aplicación
36
+ * @returns {Object|null} - La instancia de Vue o null si no está disponible
37
+ */
38
+ export function getVueInstance() {
39
+ // Intentar obtener la instancia desde diferentes fuentes
40
+ if (typeof window !== 'undefined') {
41
+ // Primero intentar desde window.__VUE_APP__
42
+ if (window.__VUE_APP__) {
43
+ return window.__VUE_APP__;
44
+ }
45
+
46
+ // Luego intentar desde window.__VUE_APP_INSTANCE__
47
+ if (
48
+ window.__VUE_APP_INSTANCE__ &&
49
+ typeof window.__VUE_APP_INSTANCE__.get === 'function'
50
+ ) {
51
+ return window.__VUE_APP_INSTANCE__.get();
52
+ }
53
+ }
54
+
55
+ // Finalmente intentar desde instanciaVue
56
+ return instanciaVue.methods.get();
57
+ }