versacompiler 1.0.3 → 1.0.4
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 +249 -0
- package/dist/hrm/errorScreen.js +61 -0
- package/dist/hrm/instanciaVue.js +35 -0
- package/dist/hrm/setupHMR.js +57 -0
- package/dist/index.js +87 -6
- package/dist/services/acorn.js +2 -1
- package/dist/services/vueLoader.js +324 -0
- package/dist/services/vuejs.js +38 -14
- package/package.json +10 -8
|
@@ -0,0 +1,249 @@
|
|
|
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
|
+
const newBaseUrl = new URL(baseUrl);
|
|
130
|
+
const urlOrigin = `${newBaseUrl.origin}/${relativePath}`;
|
|
131
|
+
const module = await import(`${urlOrigin}?t=${Date.now()}`);
|
|
132
|
+
currentComponentTree = buildComponentTree(app._instance);
|
|
133
|
+
|
|
134
|
+
const targetNode = findNodeByInstance(
|
|
135
|
+
currentComponentTree,
|
|
136
|
+
componentName,
|
|
137
|
+
);
|
|
138
|
+
const path = getPathToRoot(targetNode);
|
|
139
|
+
for (const instanciaParent of path) {
|
|
140
|
+
if (
|
|
141
|
+
instanciaParent.isRoot ||
|
|
142
|
+
instanciaParent.name === 'KeepAlive'
|
|
143
|
+
) {
|
|
144
|
+
window.location.reload();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (instanciaParent.name !== componentName) {
|
|
148
|
+
if (
|
|
149
|
+
instanciaParent.name !== 'BaseTransition' &&
|
|
150
|
+
instanciaParent.name !== 'Transition' &&
|
|
151
|
+
instanciaParent.name !== 'Suspense'
|
|
152
|
+
) {
|
|
153
|
+
const componentsDefinition =
|
|
154
|
+
instanciaParent.instancia?.type?.components ||
|
|
155
|
+
instanciaParent.instancia?.components;
|
|
156
|
+
|
|
157
|
+
if (
|
|
158
|
+
componentsDefinition &&
|
|
159
|
+
componentsDefinition[componentName]
|
|
160
|
+
) {
|
|
161
|
+
componentsDefinition[componentName] = module.default;
|
|
162
|
+
if (tryForceUpdate(instanciaParent.instancia)) {
|
|
163
|
+
console.log(
|
|
164
|
+
`✔️ Versa HMR: Component updated successfully`,
|
|
165
|
+
);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.log(error.stack);
|
|
175
|
+
return {
|
|
176
|
+
msg: `Error al recargar ${componentName}: ${error}`,
|
|
177
|
+
error,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Función Debounce
|
|
183
|
+
export function debounce(func, waitFor) {
|
|
184
|
+
let timeout = null;
|
|
185
|
+
|
|
186
|
+
const debounced = (...args) => {
|
|
187
|
+
if (timeout) {
|
|
188
|
+
clearTimeout(timeout);
|
|
189
|
+
}
|
|
190
|
+
timeout = setTimeout(() => func(...args), waitFor);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return debounced;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function reloadJS(_relativePath) {
|
|
197
|
+
location.reload();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function socketReload(app) {
|
|
201
|
+
if (window.___browserSync___?.socket) {
|
|
202
|
+
const socket = window.___browserSync___.socket;
|
|
203
|
+
// Configura el observer para actualizar el árbol de componentes en cada mutación relevante
|
|
204
|
+
if (app && app._container) {
|
|
205
|
+
currentComponentTree = buildComponentTree(app._instance);
|
|
206
|
+
initializeMutationObserver(app._container, () => {
|
|
207
|
+
if (app._instance) {
|
|
208
|
+
currentComponentTree = buildComponentTree(app._instance);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
socket.on('vue:update', data => {
|
|
213
|
+
console.log('pasa');
|
|
214
|
+
if (document.querySelector('#versa-hmr-error-overlay')) {
|
|
215
|
+
window.location.reload();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const { component, relativePath, extension, type, timestamp } =
|
|
220
|
+
data;
|
|
221
|
+
if (extension === 'vue') {
|
|
222
|
+
reloadComponent(
|
|
223
|
+
app,
|
|
224
|
+
component,
|
|
225
|
+
`/${relativePath}`,
|
|
226
|
+
type,
|
|
227
|
+
extension,
|
|
228
|
+
);
|
|
229
|
+
} else {
|
|
230
|
+
reloadJS(`/${relativePath}?t=${timestamp}`);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
} else {
|
|
234
|
+
setTimeout(() => {
|
|
235
|
+
window.location.reload();
|
|
236
|
+
}, 5000);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function initializeMutationObserver(targetNode, callback, options) {
|
|
241
|
+
const observerInstance = new MutationObserver(callback);
|
|
242
|
+
const defaultOptions = {
|
|
243
|
+
childList: true,
|
|
244
|
+
subtree: true,
|
|
245
|
+
attributes: false,
|
|
246
|
+
};
|
|
247
|
+
observerInstance.observe(targetNode, { ...defaultOptions, ...options });
|
|
248
|
+
return observerInstance;
|
|
249
|
+
}
|
|
@@ -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
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
writeFile,
|
|
16
16
|
} from 'node:fs/promises';
|
|
17
17
|
import path from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname = path.dirname(__filename);
|
|
18
22
|
|
|
19
23
|
import { checkSintaxysAcorn } from './services/acorn.js';
|
|
20
24
|
import { linter } from './services/linter.js';
|
|
@@ -161,9 +165,19 @@ const deleteFile = async ruta => {
|
|
|
161
165
|
)
|
|
162
166
|
).toString();
|
|
163
167
|
try {
|
|
164
|
-
log(chalk.yellow(`🗑️ :
|
|
168
|
+
log(chalk.yellow(`🗑️ :Intentando eliminar ${newPath}`));
|
|
169
|
+
|
|
170
|
+
const stats = await stat(newPath).catch(() => null);
|
|
171
|
+
|
|
172
|
+
if (!stats) {
|
|
173
|
+
log(
|
|
174
|
+
chalk.yellow(
|
|
175
|
+
`⚠️ :El archivo o directorio no existe: ${newPath}`,
|
|
176
|
+
),
|
|
177
|
+
);
|
|
178
|
+
return { extension: null, normalizedPath: null, fileName: null };
|
|
179
|
+
}
|
|
165
180
|
|
|
166
|
-
const stats = await stat(newPath);
|
|
167
181
|
if (stats.isDirectory()) {
|
|
168
182
|
await rmdir(newPath, { recursive: true });
|
|
169
183
|
} else if (stats.isFile()) {
|
|
@@ -186,9 +200,10 @@ const deleteFile = async ruta => {
|
|
|
186
200
|
} catch (errora) {
|
|
187
201
|
error(
|
|
188
202
|
chalk.red(
|
|
189
|
-
`🚩 :Error al eliminar el archivo/directorio ${newPath}: ${errora}\n`,
|
|
203
|
+
`🚩 :Error al eliminar el archivo/directorio ${newPath}: ${errora.message}\n`,
|
|
190
204
|
),
|
|
191
205
|
);
|
|
206
|
+
return { extension: null, normalizedPath: null, fileName: null }; // Asegurar que se devuelve un objeto en caso de otros errores
|
|
192
207
|
}
|
|
193
208
|
};
|
|
194
209
|
|
|
@@ -697,13 +712,20 @@ const initChokidar = async () => {
|
|
|
697
712
|
port: uiPort, // Puerto aleatorio para la interfaz de usuario
|
|
698
713
|
},
|
|
699
714
|
socket: {
|
|
700
|
-
domain: `localhost:${port}`, //
|
|
715
|
+
// domain: `localhost:${port}`, // Dominio para la conexión de socket
|
|
701
716
|
path: '/browser-sync/socket.io', // Ruta correcta para socket.io
|
|
702
717
|
},
|
|
703
718
|
snippetOptions: {
|
|
704
719
|
rule: {
|
|
705
720
|
match: /<\/body>/i,
|
|
706
|
-
fn: (snippet, match) =>
|
|
721
|
+
fn: (snippet, match) => {
|
|
722
|
+
console.log(
|
|
723
|
+
'🟢 Inyectando snippet de BrowserSync y vueLoader.js en el HTML',
|
|
724
|
+
);
|
|
725
|
+
return `${snippet}${match}
|
|
726
|
+
<script type="module" src="/__versa/vueLoader.js"></script>
|
|
727
|
+
`;
|
|
728
|
+
},
|
|
707
729
|
},
|
|
708
730
|
},
|
|
709
731
|
logLevel: 'debug',
|
|
@@ -713,12 +735,68 @@ const initChokidar = async () => {
|
|
|
713
735
|
watchEvents: ['change', 'add', 'unlink', 'addDir', 'unlinkDir'],
|
|
714
736
|
reloadDelay: 500,
|
|
715
737
|
reloadDebounce: 500,
|
|
738
|
+
reloadOnRestart: true,
|
|
716
739
|
notify: true,
|
|
717
740
|
watchOptions: {
|
|
718
741
|
ignoreInitial: true,
|
|
719
742
|
ignored: ['node_modules', '.git'],
|
|
720
743
|
},
|
|
721
|
-
middleware: function (req, res, next) {
|
|
744
|
+
middleware: async function (req, res, next) {
|
|
745
|
+
// para evitar el error de CORS
|
|
746
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
747
|
+
res.setHeader('Access-Control-Allow-Methods', '*');
|
|
748
|
+
res.setHeader('Access-Control-Allow-Headers', '*');
|
|
749
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
750
|
+
res.setHeader('Access-Control-Max-Age', '3600');
|
|
751
|
+
|
|
752
|
+
//para redigir a la ubicación correcta
|
|
753
|
+
if (req.url === '/__versa/vueLoader.js') {
|
|
754
|
+
// Busca vueLoader.js en la carpeta de salida configurada
|
|
755
|
+
const vueLoaderPath = path.join(
|
|
756
|
+
__dirname,
|
|
757
|
+
'services/vueLoader.js',
|
|
758
|
+
);
|
|
759
|
+
res.setHeader('Content-Type', 'application/javascript');
|
|
760
|
+
try {
|
|
761
|
+
const fileContent = await readFile(
|
|
762
|
+
vueLoaderPath,
|
|
763
|
+
'utf-8',
|
|
764
|
+
);
|
|
765
|
+
res.end(fileContent);
|
|
766
|
+
} catch (error) {
|
|
767
|
+
console.error(
|
|
768
|
+
chalk.red(
|
|
769
|
+
`🚩 :Error al leer el archivo ${vueLoaderPath}: ${error.message}`,
|
|
770
|
+
),
|
|
771
|
+
);
|
|
772
|
+
res.statusCode = 404;
|
|
773
|
+
res.end('// vueLoader.js not found');
|
|
774
|
+
}
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
// Si la URL comienza con /__versa/hrm/, sirve los archivos de dist/hrm
|
|
778
|
+
if (req.url.startsWith('/__versa/hrm/')) {
|
|
779
|
+
// Sirve archivos de dist/hrm como /__versa/hrm/*
|
|
780
|
+
const filePath = path.join(
|
|
781
|
+
__dirname,
|
|
782
|
+
req.url.replace('/__versa/', ''),
|
|
783
|
+
);
|
|
784
|
+
res.setHeader('Content-Type', 'application/javascript');
|
|
785
|
+
try {
|
|
786
|
+
const fileContent = await readFile(filePath, 'utf-8');
|
|
787
|
+
res.end(fileContent);
|
|
788
|
+
} catch (error) {
|
|
789
|
+
console.error(
|
|
790
|
+
chalk.red(
|
|
791
|
+
`🚩 :Error al leer el archivo ${filePath}: ${error.message}`,
|
|
792
|
+
),
|
|
793
|
+
);
|
|
794
|
+
res.statusCode = 404;
|
|
795
|
+
res.end('// Not found');
|
|
796
|
+
}
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
|
|
722
800
|
// detectar si es un archivo estático, puede que contenga un . y alguna extensión o dashUsers.js?v=1746559083866
|
|
723
801
|
const isAssets = req.url.match(
|
|
724
802
|
/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|webp|avif|json|html|xml|txt|pdf|zip|mp4|mp3|wav|ogg)(\?.*)?$/i,
|
|
@@ -775,6 +853,9 @@ const initChokidar = async () => {
|
|
|
775
853
|
next();
|
|
776
854
|
},
|
|
777
855
|
});
|
|
856
|
+
console.log(
|
|
857
|
+
'🟢 BrowserSync inicializado. Esperando conexiones de socket...',
|
|
858
|
+
);
|
|
778
859
|
} catch (error) {
|
|
779
860
|
console.error(
|
|
780
861
|
chalk.red('🚩 :Error al iniciar:'),
|
package/dist/services/acorn.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as Parser from 'acorn';
|
|
2
|
+
import chalk from 'chalk';
|
|
2
3
|
/**
|
|
3
4
|
* Parses the given JavaScript code using Acorn and returns the Abstract Syntax Tree (AST).
|
|
4
5
|
*
|
|
@@ -8,7 +9,7 @@ import * as Parser from 'acorn';
|
|
|
8
9
|
*/
|
|
9
10
|
export const checkSintaxysAcorn = async data => {
|
|
10
11
|
try {
|
|
11
|
-
const ast = Parser.parse(data, {
|
|
12
|
+
const ast = await Parser.parse(data, {
|
|
12
13
|
ecmaVersion: 2020,
|
|
13
14
|
sourceType: 'module',
|
|
14
15
|
locations: true,
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
let socketReload,
|
|
2
|
+
getInstancia,
|
|
3
|
+
getVueInstance,
|
|
4
|
+
showErrorOverlay,
|
|
5
|
+
hideErrorOverlay,
|
|
6
|
+
reloadComponent,
|
|
7
|
+
reloadJS;
|
|
8
|
+
|
|
9
|
+
// En navegador: usar rutas relativas estáticas
|
|
10
|
+
(async () => {
|
|
11
|
+
try {
|
|
12
|
+
// Importa todas las dependencias HMR necesarias aquí
|
|
13
|
+
// CORREGIR RUTA DE IMPORTACIÓN PARA devMode.js
|
|
14
|
+
const devModeModule = await import('./hrm/devMode.js');
|
|
15
|
+
socketReload = devModeModule.socketReload;
|
|
16
|
+
reloadComponent = devModeModule.reloadComponent;
|
|
17
|
+
reloadJS = devModeModule.reloadJS;
|
|
18
|
+
|
|
19
|
+
// Log para verificar la carga de reloadComponent
|
|
20
|
+
if (typeof reloadComponent === 'function') {
|
|
21
|
+
console.log(
|
|
22
|
+
'[HMR] La función reloadComponent se cargó correctamente.',
|
|
23
|
+
);
|
|
24
|
+
} else {
|
|
25
|
+
console.error(
|
|
26
|
+
'[HMR] ERROR: La función reloadComponent NO se cargó o no es una función después de la importación.',
|
|
27
|
+
devModeModule,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getInstancia = (await import('./hrm/instanciaVue.js')).default; // Asumiendo que está en dist/hrm/
|
|
32
|
+
getVueInstance = (await import('./hrm/setupHMR.js')).getVueInstance; // Asumiendo que está en dist/hrm/
|
|
33
|
+
|
|
34
|
+
const errorScreenModule = await import('./hrm/errorScreen.js'); // Asumiendo que está en dist/hrm/
|
|
35
|
+
showErrorOverlay = errorScreenModule.showErrorOverlay;
|
|
36
|
+
hideErrorOverlay = errorScreenModule.hideErrorOverlay;
|
|
37
|
+
|
|
38
|
+
// Esperar a que BrowserSync client esté listo y haya definido ___browserSync___
|
|
39
|
+
let bsReadyRetries = 0;
|
|
40
|
+
const maxBsReadyRetries = 30; // 30 * 500ms = 15 segundos de espera máxima
|
|
41
|
+
const bsReadyCheckInterval = 500;
|
|
42
|
+
|
|
43
|
+
while (
|
|
44
|
+
!window.___browserSync___ &&
|
|
45
|
+
bsReadyRetries < maxBsReadyRetries
|
|
46
|
+
) {
|
|
47
|
+
console.warn(
|
|
48
|
+
`[HMR] Esperando a que el script cliente de BrowserSync se inicialice... (${
|
|
49
|
+
bsReadyRetries + 1
|
|
50
|
+
}/${maxBsReadyRetries})`,
|
|
51
|
+
);
|
|
52
|
+
await new Promise(resolve =>
|
|
53
|
+
setTimeout(resolve, bsReadyCheckInterval),
|
|
54
|
+
);
|
|
55
|
+
bsReadyRetries++;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!window.___browserSync___) {
|
|
59
|
+
console.error(
|
|
60
|
+
'❌ Versa HMR: El script cliente de BrowserSync no se inicializó después de múltiples reintentos. HMR no funcionará.',
|
|
61
|
+
);
|
|
62
|
+
if (showErrorOverlay) {
|
|
63
|
+
// Verificar si showErrorOverlay se cargó
|
|
64
|
+
showErrorOverlay(
|
|
65
|
+
'Falló la inicialización de HMR',
|
|
66
|
+
'El cliente de BrowserSync no se inicializó. Revisa la consola y el servidor de BrowserSync.',
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return; // Detener la ejecución si BrowserSync no está listo
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(
|
|
73
|
+
'✔️ Versa HMR: Cliente de BrowserSync detectado. Procediendo con la configuración de HMR.',
|
|
74
|
+
);
|
|
75
|
+
await initSocket(); // Llama a initSocket DESPUÉS de que las importaciones y la espera de BS hayan terminado
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(
|
|
78
|
+
'❌ Versa HMR: Error durante la carga dinámica de módulos o initSocket:',
|
|
79
|
+
error,
|
|
80
|
+
);
|
|
81
|
+
if (showErrorOverlay) {
|
|
82
|
+
showErrorOverlay(
|
|
83
|
+
'Falló la inicialización de HMR',
|
|
84
|
+
error.stack || error.message,
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
const errDiv = document.createElement('div');
|
|
88
|
+
errDiv.textContent =
|
|
89
|
+
'Falló la inicialización de HMR: ' + error.message;
|
|
90
|
+
errDiv.style.cssText =
|
|
91
|
+
'position:fixed;top:10px;left:10px;padding:10px;background:red;color:white;z-index:1000000;';
|
|
92
|
+
document.body.appendChild(errDiv);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})();
|
|
96
|
+
|
|
97
|
+
// Obtención robusta de la instancia de Vue
|
|
98
|
+
const getInstanceVue = async () => {
|
|
99
|
+
let instance = getVueInstance && getVueInstance();
|
|
100
|
+
if (instance) return instance;
|
|
101
|
+
if (typeof window !== 'undefined') {
|
|
102
|
+
if (window.__VUE_APP__) return window.__VUE_APP__;
|
|
103
|
+
if (
|
|
104
|
+
window.__VUE_APP_INSTANCE__ &&
|
|
105
|
+
typeof window.__VUE_APP_INSTANCE__.get === 'function'
|
|
106
|
+
) {
|
|
107
|
+
const winInstance = window.__VUE_APP_INSTANCE__.get();
|
|
108
|
+
if (winInstance) return winInstance;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
instance = getInstancia && getInstancia.methods.get();
|
|
112
|
+
if (instance) return instance;
|
|
113
|
+
return null;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Reintentos con backoff exponencial para obtener la instancia
|
|
117
|
+
async function waitForVueInstance(maxTries = 5, delay = 300) {
|
|
118
|
+
let tries = 0;
|
|
119
|
+
while (tries < maxTries) {
|
|
120
|
+
const instance = await getInstanceVue();
|
|
121
|
+
if (instance) return instance;
|
|
122
|
+
await new Promise(resolve =>
|
|
123
|
+
globalThis.setTimeout(resolve, delay * 2 ** tries),
|
|
124
|
+
);
|
|
125
|
+
tries++;
|
|
126
|
+
}
|
|
127
|
+
// Si no se encuentra, muestra overlay y no recarga
|
|
128
|
+
const errorMsg =
|
|
129
|
+
'Instancia de Vue no encontrada después de múltiples reintentos.';
|
|
130
|
+
const detailMsg =
|
|
131
|
+
'La aplicación no pudo iniciarse. Esperando una corrección para recargar.';
|
|
132
|
+
if (typeof showErrorOverlay === 'function') {
|
|
133
|
+
showErrorOverlay(errorMsg, detailMsg);
|
|
134
|
+
} else {
|
|
135
|
+
console.error(
|
|
136
|
+
'[HMR] showErrorOverlay no disponible, pero la instancia de Vue no se encontró.',
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
console.error(errorMsg);
|
|
140
|
+
return null; // Indica que falló
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Initialize socket connection and HMR con reconexión automática
|
|
144
|
+
const initSocket = async (retries = 0) => {
|
|
145
|
+
const maxRetries = 10;
|
|
146
|
+
const retryDelay = Math.min(2000 * (retries + 1), 10000); // backoff hasta 10s
|
|
147
|
+
|
|
148
|
+
// Se asume que window.___browserSync___ ya existe debido a la espera en la IIFE
|
|
149
|
+
// Pero se verifica window.___browserSync___.socket
|
|
150
|
+
if (window.___browserSync___ && window.___browserSync___.socket) {
|
|
151
|
+
const socket = window.___browserSync___.socket;
|
|
152
|
+
let connected = socket.connected; // Verificar estado inicial
|
|
153
|
+
|
|
154
|
+
// Listener para conexión
|
|
155
|
+
socket.on('connect', async () => {
|
|
156
|
+
connected = true;
|
|
157
|
+
if (typeof hideErrorOverlay === 'function') {
|
|
158
|
+
hideErrorOverlay();
|
|
159
|
+
} else {
|
|
160
|
+
console.warn(
|
|
161
|
+
'[HMR] hideErrorOverlay no es una función al momento de la conexión',
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
const vueAppInstance = await waitForVueInstance();
|
|
165
|
+
if (vueAppInstance && vueAppInstance._instance) {
|
|
166
|
+
if (typeof socketReload === 'function') {
|
|
167
|
+
socketReload(vueAppInstance);
|
|
168
|
+
} else {
|
|
169
|
+
console.warn(
|
|
170
|
+
'[HMR] socketReload no es una función al momento de la conexión',
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
console.error(
|
|
175
|
+
'❌ Versa HMR: Instancia de Vue no encontrada después de la conexión del socket',
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
console.log('✔️ Versa HMR: Socket conectado');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Listener para desconexión
|
|
182
|
+
socket.on('disconnect', () => {
|
|
183
|
+
connected = false;
|
|
184
|
+
console.log('❌ Versa HMR: Socket desconectado, reintentando...');
|
|
185
|
+
// La lógica de reintentos original para desconexión
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
if (!socket.connected && retries < maxRetries) {
|
|
188
|
+
// Usar socket.connected aquí
|
|
189
|
+
initSocket(retries + 1);
|
|
190
|
+
} else if (!socket.connected) {
|
|
191
|
+
console.error(
|
|
192
|
+
`❌ Versa HMR: Socket no conectado después de ${maxRetries} reintentos tras desconexión.`,
|
|
193
|
+
);
|
|
194
|
+
if (typeof showErrorOverlay === 'function') {
|
|
195
|
+
showErrorOverlay(
|
|
196
|
+
'HMR Desconectado',
|
|
197
|
+
'No se pudo reconectar a BrowserSync después de múltiples reintentos.',
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}, retryDelay);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
socket.on('vue:update', async data => {
|
|
205
|
+
// Log para verificar reloadComponent al inicio del evento
|
|
206
|
+
if (typeof reloadComponent !== 'function') {
|
|
207
|
+
console.error(
|
|
208
|
+
'[HMR] ERROR en vue:update: reloadComponent no es una función.',
|
|
209
|
+
);
|
|
210
|
+
if (typeof showErrorOverlay === 'function') {
|
|
211
|
+
showErrorOverlay(
|
|
212
|
+
'Error Crítico de HMR',
|
|
213
|
+
'reloadComponent no está disponible. Verifique la consola para errores de carga.',
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (typeof hideErrorOverlay === 'function') hideErrorOverlay();
|
|
220
|
+
else
|
|
221
|
+
console.warn(
|
|
222
|
+
'[HMR] hideErrorOverlay no disponible en vue:update',
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const { component, relativePath, extension, type, timestamp } =
|
|
226
|
+
data;
|
|
227
|
+
const appInstance = await getInstanceVue();
|
|
228
|
+
|
|
229
|
+
if (!appInstance) {
|
|
230
|
+
// Si la instancia de Vue no existe, la carga inicial probablemente falló.
|
|
231
|
+
// Una actualización de módulo (presumiblemente la corrección del error) ha llegado.
|
|
232
|
+
// Recargar la página completa para permitir que vue-loader.ts intente de nuevo.
|
|
233
|
+
console.log(
|
|
234
|
+
'[HMR] La instancia de Vue no existe (posible fallo en la carga inicial). Se recibió una actualización de módulo. Recargando la página...',
|
|
235
|
+
);
|
|
236
|
+
window.location.reload();
|
|
237
|
+
return; // Detener la ejecución adicional de HMR para esta actualización.
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
if (extension === 'vue') {
|
|
242
|
+
const result = await reloadComponent(
|
|
243
|
+
appInstance,
|
|
244
|
+
component,
|
|
245
|
+
`${relativePath}`,
|
|
246
|
+
type,
|
|
247
|
+
extension,
|
|
248
|
+
);
|
|
249
|
+
if (result && result.msg) {
|
|
250
|
+
throw new Error(result.msg);
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
// Asumiendo que reloadJS existe
|
|
254
|
+
await reloadJS(`/${relativePath}?t=${timestamp}`);
|
|
255
|
+
}
|
|
256
|
+
} catch (hmrError) {
|
|
257
|
+
const errorMsg = `HMR falló para ${relativePath}`;
|
|
258
|
+
const errorStack =
|
|
259
|
+
hmrError.stack ||
|
|
260
|
+
(hmrError.toString
|
|
261
|
+
? hmrError.toString()
|
|
262
|
+
: 'No hay stack disponible');
|
|
263
|
+
if (typeof showErrorOverlay === 'function') {
|
|
264
|
+
showErrorOverlay(errorMsg, errorStack);
|
|
265
|
+
} else {
|
|
266
|
+
console.error(
|
|
267
|
+
'[HMR] showErrorOverlay no disponible. Error HMR:',
|
|
268
|
+
errorMsg,
|
|
269
|
+
hmrError,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
console.error(errorMsg, hmrError);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Watchdog para la conexión inicial si el socket existe pero no está conectado
|
|
277
|
+
if (!connected) {
|
|
278
|
+
console.log(
|
|
279
|
+
`Versa HMR: Objeto socket encontrado, intentando conexión (Intento ${
|
|
280
|
+
retries + 1
|
|
281
|
+
}/${maxRetries})`,
|
|
282
|
+
);
|
|
283
|
+
setTimeout(() => {
|
|
284
|
+
if (!socket.connected && retries < maxRetries) {
|
|
285
|
+
console.warn(
|
|
286
|
+
'Versa HMR: Sin conexión de socket después del tiempo de espera inicial, reintentando initSocket...',
|
|
287
|
+
);
|
|
288
|
+
initSocket(retries + 1);
|
|
289
|
+
} else if (!socket.connected) {
|
|
290
|
+
console.error(
|
|
291
|
+
`❌ Versa HMR: Socket aún no conectado después de ${maxRetries} intentos iniciales.`,
|
|
292
|
+
);
|
|
293
|
+
if (typeof showErrorOverlay === 'function') {
|
|
294
|
+
showErrorOverlay(
|
|
295
|
+
'Falló HMR de BrowserSync',
|
|
296
|
+
'No se pudo conectar al socket de BrowserSync después de intentos iniciales.',
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}, 5000); // Timeout de 5s para el watchdog inicial
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
// Este bloque se ejecuta si window.___browserSync___ existe pero window.___browserSync___.socket no,
|
|
304
|
+
// o si window.___browserSync___ no existe (aunque la IIFE debería haberlo esperado).
|
|
305
|
+
console.warn(
|
|
306
|
+
`[HMR] Socket de BrowserSync no encontrado o BrowserSync no completamente inicializado. Reintentando initSocket... (${
|
|
307
|
+
retries + 1
|
|
308
|
+
}/${maxRetries})`,
|
|
309
|
+
);
|
|
310
|
+
if (retries < maxRetries) {
|
|
311
|
+
setTimeout(() => initSocket(retries + 1), retryDelay);
|
|
312
|
+
} else {
|
|
313
|
+
console.error(
|
|
314
|
+
`❌ Versa HMR: Socket de BrowserSync no encontrado después de ${maxRetries} reintentos.`,
|
|
315
|
+
);
|
|
316
|
+
if (typeof showErrorOverlay === 'function') {
|
|
317
|
+
showErrorOverlay(
|
|
318
|
+
'Falló HMR de BrowserSync',
|
|
319
|
+
'Socket o cliente de BrowserSync no encontrado después de múltiples reintentos.',
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
};
|
package/dist/services/vuejs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as vCompiler from 'vue/compiler-sfc';
|
|
2
1
|
import path from 'node:path';
|
|
2
|
+
import * as vCompiler from 'vue/compiler-sfc';
|
|
3
3
|
|
|
4
4
|
const getComponentsVue = async data => {
|
|
5
5
|
let components = [];
|
|
@@ -40,6 +40,34 @@ const _compileCustomBlock = async (_block, _source) => {};
|
|
|
40
40
|
export const preCompileVue = async (data, source, isProd = false) => {
|
|
41
41
|
try {
|
|
42
42
|
const fileName = path.basename(source).replace('.vue', '');
|
|
43
|
+
|
|
44
|
+
if (!isProd) {
|
|
45
|
+
const ifExistsref = data.includes('ref(');
|
|
46
|
+
|
|
47
|
+
// esto es para HMR re re forzado
|
|
48
|
+
const varContent = `
|
|
49
|
+
${ifExistsref ? '' : 'import { ref } from "vue";'};
|
|
50
|
+
const versaComponentKey = ref(0);
|
|
51
|
+
`;
|
|
52
|
+
const ifExistScript = data.includes('<script');
|
|
53
|
+
if (!ifExistScript) {
|
|
54
|
+
data = `<script setup>${varContent}</script>` + data;
|
|
55
|
+
} else {
|
|
56
|
+
data = data.replace(/(<script.*?>)/, `$1${varContent}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
data = data.replace(
|
|
60
|
+
/(<template>[\s\S]*?)(<\w+)([^>]*)(\/?>)/,
|
|
61
|
+
(match, p1, p2, p3, p4) => {
|
|
62
|
+
// Si es self-closing (termina con '/>'), no agregar key
|
|
63
|
+
const existeSlash = p3.trim().slice(-1) === '/';
|
|
64
|
+
|
|
65
|
+
return `${p1} ${p2} ${existeSlash ? p3.trim().slice(0, -1) : p3} :key="versaComponentKey" ${existeSlash ? '/' : ''}${p4}`;
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
// console.log(data);
|
|
69
|
+
}
|
|
70
|
+
|
|
43
71
|
const { descriptor, errors } = vCompiler.parse(data, {
|
|
44
72
|
filename: fileName,
|
|
45
73
|
sourceMap: false,
|
|
@@ -163,9 +191,6 @@ export const preCompileVue = async (data, source, isProd = false) => {
|
|
|
163
191
|
${compiledScript.content}
|
|
164
192
|
${compiledTemplate.code}
|
|
165
193
|
`;
|
|
166
|
-
//añardir instancia de app
|
|
167
|
-
|
|
168
|
-
// output = `${appImport}${output}`;
|
|
169
194
|
|
|
170
195
|
const componentName = `${fileName}_component`;
|
|
171
196
|
const components = await getComponentsVue(data);
|
|
@@ -173,7 +198,9 @@ export const preCompileVue = async (data, source, isProd = false) => {
|
|
|
173
198
|
__file: '${source}',
|
|
174
199
|
__name: '${fileName}',
|
|
175
200
|
name: '${fileName}',
|
|
176
|
-
components: {
|
|
201
|
+
components: {
|
|
202
|
+
${components}
|
|
203
|
+
},
|
|
177
204
|
`;
|
|
178
205
|
|
|
179
206
|
// quitamos export default y añadimos el nombre del archivo
|
|
@@ -198,12 +225,16 @@ export const preCompileVue = async (data, source, isProd = false) => {
|
|
|
198
225
|
output = output.replaceAll(/_ctx\.(?!\$)/g, '$setup.');
|
|
199
226
|
output = output.replace(
|
|
200
227
|
'export function render(_ctx, _cache) {',
|
|
201
|
-
`
|
|
228
|
+
`
|
|
229
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
230
|
+
`,
|
|
202
231
|
);
|
|
203
232
|
} else {
|
|
204
233
|
output = output.replace(
|
|
205
234
|
'export function render(_ctx, _cache) {',
|
|
206
|
-
`
|
|
235
|
+
`
|
|
236
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
237
|
+
`,
|
|
207
238
|
);
|
|
208
239
|
}
|
|
209
240
|
|
|
@@ -217,13 +248,6 @@ export const preCompileVue = async (data, source, isProd = false) => {
|
|
|
217
248
|
|
|
218
249
|
output = `${output}\n${finishComponent}`;
|
|
219
250
|
|
|
220
|
-
// await writeFile(
|
|
221
|
-
// `./public/dashboard/js/${fileName}-temp.js`,
|
|
222
|
-
// output,
|
|
223
|
-
// 'utf-8',
|
|
224
|
-
// );
|
|
225
|
-
// await unlink(`./public/dashboard/js/${fileName}-temp.js`);
|
|
226
|
-
|
|
227
251
|
return {
|
|
228
252
|
lang: compiledScript.lang,
|
|
229
253
|
error: null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "versacompiler",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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": {
|
|
@@ -32,19 +32,21 @@
|
|
|
32
32
|
"author": "Jorge Jara H (kriollone@gmail.com)",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"acorn": "^8.14.1",
|
|
36
|
+
"browser-sync": "^3.0.4",
|
|
35
37
|
"chalk": "5.4.1",
|
|
36
38
|
"chokidar": "^4.0.3",
|
|
37
|
-
"oxc-minify": "^0.68.1",
|
|
38
|
-
"acorn": "^8.14.1",
|
|
39
|
-
"vue": "3.5.13",
|
|
40
39
|
"get-port": "^7.1.0",
|
|
40
|
+
"oxc-minify": "^0.69.0",
|
|
41
41
|
"typescript": "^5.8.3",
|
|
42
|
-
"
|
|
43
|
-
"browser-sync": "^3.0.4"
|
|
42
|
+
"vue": "3.5.13"
|
|
44
43
|
},
|
|
45
44
|
"devDependencies": {
|
|
46
|
-
"
|
|
45
|
+
"@tailwindcss/cli": "^4.1.6",
|
|
47
46
|
"@types/node": "^22.15.17",
|
|
48
|
-
"code-tag": "^1.2.0"
|
|
47
|
+
"code-tag": "^1.2.0",
|
|
48
|
+
"oxlint": "^0.16.10",
|
|
49
|
+
"prettier": "3.5.3",
|
|
50
|
+
"tailwindcss": "^4.1.6"
|
|
49
51
|
}
|
|
50
52
|
}
|