wu-framework 1.0.0
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/LICENSE +21 -0
- package/README.md +559 -0
- package/package.json +84 -0
- package/src/api/wu-simple.js +316 -0
- package/src/core/wu-app.js +192 -0
- package/src/core/wu-cache.js +374 -0
- package/src/core/wu-core.js +1296 -0
- package/src/core/wu-error-boundary.js +380 -0
- package/src/core/wu-event-bus.js +257 -0
- package/src/core/wu-hooks.js +348 -0
- package/src/core/wu-html-parser.js +280 -0
- package/src/core/wu-loader.js +271 -0
- package/src/core/wu-logger.js +119 -0
- package/src/core/wu-manifest.js +366 -0
- package/src/core/wu-performance.js +226 -0
- package/src/core/wu-plugin.js +213 -0
- package/src/core/wu-proxy-sandbox.js +153 -0
- package/src/core/wu-registry.js +130 -0
- package/src/core/wu-sandbox-pool.js +390 -0
- package/src/core/wu-sandbox.js +720 -0
- package/src/core/wu-script-executor.js +216 -0
- package/src/core/wu-snapshot-sandbox.js +184 -0
- package/src/core/wu-store.js +297 -0
- package/src/core/wu-strategies.js +241 -0
- package/src/core/wu-style-bridge.js +357 -0
- package/src/index.js +690 -0
- package/src/utils/dependency-resolver.js +326 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🚀 WU-LOADER: SISTEMA DE CARGA DINÁMICA UNIVERSAL
|
|
3
|
+
* Carga aplicaciones y componentes sin depender del framework
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class WuLoader {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.cache = new Map();
|
|
9
|
+
this.loadingPromises = new Map();
|
|
10
|
+
|
|
11
|
+
console.log('[WuLoader] 📦 Dynamic loader initialized');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Cargar aplicación completa
|
|
16
|
+
* @param {string} appUrl - URL base de la aplicación
|
|
17
|
+
* @param {Object} manifest - Manifest de la aplicación
|
|
18
|
+
* @returns {string} Código JavaScript de la aplicación
|
|
19
|
+
*/
|
|
20
|
+
async loadApp(appUrl, manifest) {
|
|
21
|
+
const entryFile = manifest?.entry || 'index.js';
|
|
22
|
+
const fullUrl = `${appUrl}/${entryFile}`;
|
|
23
|
+
|
|
24
|
+
console.log(`[WuLoader] 📥 Loading app from: ${fullUrl}`);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Verificar cache
|
|
28
|
+
if (this.cache.has(fullUrl)) {
|
|
29
|
+
console.log(`[WuLoader] ⚡ Cache hit for: ${fullUrl}`);
|
|
30
|
+
return this.cache.get(fullUrl);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Verificar si ya está cargando
|
|
34
|
+
if (this.loadingPromises.has(fullUrl)) {
|
|
35
|
+
console.log(`[WuLoader] ⏳ Loading in progress for: ${fullUrl}`);
|
|
36
|
+
return await this.loadingPromises.get(fullUrl);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Crear promesa de carga
|
|
40
|
+
const loadingPromise = this.fetchCode(fullUrl);
|
|
41
|
+
this.loadingPromises.set(fullUrl, loadingPromise);
|
|
42
|
+
|
|
43
|
+
const code = await loadingPromise;
|
|
44
|
+
|
|
45
|
+
// Limpiar promesa de carga y cachear resultado
|
|
46
|
+
this.loadingPromises.delete(fullUrl);
|
|
47
|
+
this.cache.set(fullUrl, code);
|
|
48
|
+
|
|
49
|
+
console.log(`[WuLoader] ✅ App loaded successfully: ${fullUrl}`);
|
|
50
|
+
return code;
|
|
51
|
+
|
|
52
|
+
} catch (error) {
|
|
53
|
+
this.loadingPromises.delete(fullUrl);
|
|
54
|
+
console.error(`[WuLoader] ❌ Failed to load app: ${fullUrl}`, error);
|
|
55
|
+
throw new Error(`Failed to load app from ${fullUrl}: ${error.message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Cargar componente específico
|
|
61
|
+
* @param {string} appUrl - URL base de la aplicación
|
|
62
|
+
* @param {string} componentPath - Ruta del componente
|
|
63
|
+
* @returns {Function} Función del componente
|
|
64
|
+
*/
|
|
65
|
+
async loadComponent(appUrl, componentPath) {
|
|
66
|
+
// Normalizar ruta del componente
|
|
67
|
+
let normalizedPath = componentPath;
|
|
68
|
+
if (normalizedPath.startsWith('./')) {
|
|
69
|
+
normalizedPath = normalizedPath.substring(2);
|
|
70
|
+
}
|
|
71
|
+
if (!normalizedPath.endsWith('.js') && !normalizedPath.endsWith('.jsx')) {
|
|
72
|
+
normalizedPath += '.js';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fullUrl = `${appUrl}/${normalizedPath}`;
|
|
76
|
+
|
|
77
|
+
console.log(`[WuLoader] 🧩 Loading component from: ${fullUrl}`);
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
// Cargar código del componente
|
|
81
|
+
const code = await this.loadCode(fullUrl);
|
|
82
|
+
|
|
83
|
+
// Crear función que retorna el componente
|
|
84
|
+
const componentFunction = new Function('require', 'module', 'exports', `
|
|
85
|
+
${code}
|
|
86
|
+
return typeof module.exports === 'function' ? module.exports :
|
|
87
|
+
typeof module.exports === 'object' && module.exports.default ? module.exports.default :
|
|
88
|
+
exports.default || exports;
|
|
89
|
+
`);
|
|
90
|
+
|
|
91
|
+
// Ejecutar y obtener el componente
|
|
92
|
+
const fakeModule = { exports: {} };
|
|
93
|
+
const fakeRequire = (name) => {
|
|
94
|
+
console.warn(`[WuLoader] Component ${componentPath} requires ${name} - not supported yet`);
|
|
95
|
+
return {};
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const component = componentFunction(fakeRequire, fakeModule, fakeModule.exports);
|
|
99
|
+
|
|
100
|
+
console.log(`[WuLoader] ✅ Component loaded: ${componentPath}`);
|
|
101
|
+
return component;
|
|
102
|
+
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(`[WuLoader] ❌ Failed to load component: ${componentPath}`, error);
|
|
105
|
+
throw new Error(`Failed to load component ${componentPath}: ${error.message}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Cargar código con cache
|
|
111
|
+
* @param {string} url - URL del archivo
|
|
112
|
+
* @returns {string} Código JavaScript
|
|
113
|
+
*/
|
|
114
|
+
async loadCode(url) {
|
|
115
|
+
// Verificar cache
|
|
116
|
+
if (this.cache.has(url)) {
|
|
117
|
+
return this.cache.get(url);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Verificar si ya está cargando
|
|
121
|
+
if (this.loadingPromises.has(url)) {
|
|
122
|
+
return await this.loadingPromises.get(url);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Crear promesa de carga
|
|
126
|
+
const loadingPromise = this.fetchCode(url);
|
|
127
|
+
this.loadingPromises.set(url, loadingPromise);
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const code = await loadingPromise;
|
|
131
|
+
this.loadingPromises.delete(url);
|
|
132
|
+
this.cache.set(url, code);
|
|
133
|
+
return code;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
this.loadingPromises.delete(url);
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Realizar fetch del código
|
|
142
|
+
* @param {string} url - URL del archivo
|
|
143
|
+
* @returns {string} Código JavaScript
|
|
144
|
+
*/
|
|
145
|
+
async fetchCode(url) {
|
|
146
|
+
const response = await fetch(url, {
|
|
147
|
+
cache: 'no-cache',
|
|
148
|
+
headers: {
|
|
149
|
+
'Accept': 'application/javascript, text/javascript, */*'
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const code = await response.text();
|
|
158
|
+
|
|
159
|
+
if (!code.trim()) {
|
|
160
|
+
throw new Error('Empty response');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return code;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Precargar aplicaciones
|
|
168
|
+
* @param {Array} appConfigs - Configuraciones de aplicaciones
|
|
169
|
+
*/
|
|
170
|
+
async preload(appConfigs) {
|
|
171
|
+
console.log(`[WuLoader] 🚀 Preloading ${appConfigs.length} apps...`);
|
|
172
|
+
|
|
173
|
+
const preloadPromises = appConfigs.map(async (config) => {
|
|
174
|
+
try {
|
|
175
|
+
await this.loadApp(config.url, config.manifest);
|
|
176
|
+
console.log(`[WuLoader] ✅ Preloaded: ${config.name}`);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.warn(`[WuLoader] ⚠️ Failed to preload ${config.name}:`, error.message);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
await Promise.allSettled(preloadPromises);
|
|
183
|
+
console.log(`[WuLoader] 🎉 Preload completed`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Verificar si una URL está disponible
|
|
188
|
+
* @param {string} url - URL a verificar
|
|
189
|
+
* @returns {boolean} True si está disponible
|
|
190
|
+
*/
|
|
191
|
+
async isAvailable(url) {
|
|
192
|
+
try {
|
|
193
|
+
const response = await fetch(url, { method: 'HEAD' });
|
|
194
|
+
return response.ok;
|
|
195
|
+
} catch {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Resolver dependencias de imports
|
|
202
|
+
* @param {Array} imports - Lista de imports del manifest
|
|
203
|
+
* @param {Map} availableApps - Apps disponibles
|
|
204
|
+
*/
|
|
205
|
+
async resolveDependencies(imports, availableApps) {
|
|
206
|
+
const resolved = new Map();
|
|
207
|
+
|
|
208
|
+
for (const importPath of imports || []) {
|
|
209
|
+
const [appName, componentName] = importPath.split('.');
|
|
210
|
+
|
|
211
|
+
if (!appName || !componentName) {
|
|
212
|
+
console.warn(`[WuLoader] Invalid import format: ${importPath}`);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const app = availableApps.get(appName);
|
|
217
|
+
if (!app) {
|
|
218
|
+
console.warn(`[WuLoader] Import app not found: ${appName}`);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const manifest = app.manifest;
|
|
223
|
+
const exportPath = manifest?.wu?.exports?.[componentName];
|
|
224
|
+
|
|
225
|
+
if (!exportPath) {
|
|
226
|
+
console.warn(`[WuLoader] Export not found: ${importPath}`);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
const component = await this.loadComponent(app.url, exportPath);
|
|
232
|
+
resolved.set(importPath, component);
|
|
233
|
+
console.log(`[WuLoader] ✅ Resolved dependency: ${importPath}`);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error(`[WuLoader] ❌ Failed to resolve: ${importPath}`, error);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return resolved;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Limpiar cache
|
|
244
|
+
* @param {string} pattern - Patrón opcional para limpiar URLs específicas
|
|
245
|
+
*/
|
|
246
|
+
clearCache(pattern) {
|
|
247
|
+
if (pattern) {
|
|
248
|
+
const regex = new RegExp(pattern);
|
|
249
|
+
for (const [url] of this.cache) {
|
|
250
|
+
if (regex.test(url)) {
|
|
251
|
+
this.cache.delete(url);
|
|
252
|
+
console.log(`[WuLoader] 🗑️ Cleared cache for: ${url}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
this.cache.clear();
|
|
257
|
+
console.log(`[WuLoader] 🗑️ Cache cleared completely`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Obtener estadísticas del loader
|
|
263
|
+
*/
|
|
264
|
+
getStats() {
|
|
265
|
+
return {
|
|
266
|
+
cached: this.cache.size,
|
|
267
|
+
loading: this.loadingPromises.size,
|
|
268
|
+
cacheKeys: Array.from(this.cache.keys())
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 📝 WU-LOGGER: Sistema de logging inteligente para entornos
|
|
3
|
+
* Controla los logs automáticamente según el entorno
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class WuLogger {
|
|
7
|
+
constructor() {
|
|
8
|
+
// Detectar entorno automáticamente
|
|
9
|
+
this.isDevelopment = this.detectEnvironment();
|
|
10
|
+
this.logLevel = this.isDevelopment ? 'debug' : 'error';
|
|
11
|
+
|
|
12
|
+
this.levels = {
|
|
13
|
+
debug: 0,
|
|
14
|
+
info: 1,
|
|
15
|
+
warn: 2,
|
|
16
|
+
error: 3,
|
|
17
|
+
silent: 4
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Detectar si estamos en desarrollo
|
|
23
|
+
*/
|
|
24
|
+
detectEnvironment() {
|
|
25
|
+
// Múltiples formas de detectar desarrollo
|
|
26
|
+
return (
|
|
27
|
+
// Vite development
|
|
28
|
+
window.location.hostname === 'localhost' ||
|
|
29
|
+
window.location.hostname === '127.0.0.1' ||
|
|
30
|
+
window.location.port !== '' ||
|
|
31
|
+
// NODE_ENV si está disponible
|
|
32
|
+
(typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') ||
|
|
33
|
+
// URL params para forzar debug
|
|
34
|
+
new URLSearchParams(window.location.search).has('wu-debug') ||
|
|
35
|
+
// Manual override
|
|
36
|
+
window.WU_DEBUG === true
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Configurar nivel de logging
|
|
42
|
+
*/
|
|
43
|
+
setLevel(level) {
|
|
44
|
+
this.logLevel = level;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Habilitar/deshabilitar development mode
|
|
50
|
+
*/
|
|
51
|
+
setDevelopment(isDev) {
|
|
52
|
+
this.isDevelopment = isDev;
|
|
53
|
+
this.logLevel = isDev ? 'debug' : 'error';
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Verificar si debemos mostrar el log
|
|
59
|
+
*/
|
|
60
|
+
shouldLog(level) {
|
|
61
|
+
return this.levels[level] >= this.levels[this.logLevel];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Logging methods
|
|
66
|
+
*/
|
|
67
|
+
debug(...args) {
|
|
68
|
+
if (this.shouldLog('debug')) {
|
|
69
|
+
console.log(...args);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
info(...args) {
|
|
74
|
+
if (this.shouldLog('info')) {
|
|
75
|
+
console.info(...args);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
warn(...args) {
|
|
80
|
+
if (this.shouldLog('warn')) {
|
|
81
|
+
console.warn(...args);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
error(...args) {
|
|
86
|
+
if (this.shouldLog('error')) {
|
|
87
|
+
console.error(...args);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Logging con contexto Wu
|
|
93
|
+
*/
|
|
94
|
+
wu(level, ...args) {
|
|
95
|
+
if (this.shouldLog(level)) {
|
|
96
|
+
const method = level === 'debug' ? 'log' : level;
|
|
97
|
+
console[method]('[Wu]', ...args);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Helper methods específicos para Wu
|
|
103
|
+
*/
|
|
104
|
+
wuDebug(...args) { this.wu('debug', ...args); }
|
|
105
|
+
wuInfo(...args) { this.wu('info', ...args); }
|
|
106
|
+
wuWarn(...args) { this.wu('warn', ...args); }
|
|
107
|
+
wuError(...args) { this.wu('error', ...args); }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Singleton instance
|
|
111
|
+
export const logger = new WuLogger();
|
|
112
|
+
|
|
113
|
+
// Helper para compatibilidad con logs existentes
|
|
114
|
+
export const wuLog = {
|
|
115
|
+
debug: (...args) => logger.wuDebug(...args),
|
|
116
|
+
info: (...args) => logger.wuInfo(...args),
|
|
117
|
+
warn: (...args) => logger.wuWarn(...args),
|
|
118
|
+
error: (...args) => logger.wuError(...args)
|
|
119
|
+
};
|