wu-framework 1.0.6 → 1.1.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/README.md +773 -366
- package/package.json +34 -9
- package/src/adapters/angular.d.ts +154 -0
- package/src/adapters/angular.js +642 -0
- package/src/adapters/index.js +157 -0
- package/src/adapters/lit.d.ts +120 -0
- package/src/adapters/lit.js +726 -0
- package/src/adapters/preact.d.ts +108 -0
- package/src/adapters/preact.js +665 -0
- package/src/adapters/react.d.ts +212 -0
- package/src/adapters/react.js +513 -0
- package/src/adapters/solid.d.ts +101 -0
- package/src/adapters/solid.js +591 -0
- package/src/adapters/svelte.d.ts +166 -0
- package/src/adapters/svelte.js +803 -0
- package/src/adapters/vanilla.d.ts +179 -0
- package/src/adapters/vanilla.js +791 -0
- package/src/adapters/vue.d.ts +299 -0
- package/src/adapters/vue.js +570 -0
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🚀 WU-FRAMEWORK ANGULAR ADAPTER
|
|
3
|
+
*
|
|
4
|
+
* Simplifica la integración de Angular con Wu Framework.
|
|
5
|
+
* Convierte componentes Angular en microfrontends con configuración mínima.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Microfrontend (main.ts)
|
|
9
|
+
* import { wuAngular } from 'wu-framework/adapters/angular';
|
|
10
|
+
* import { AppModule } from './app/app.module';
|
|
11
|
+
* // o para standalone components
|
|
12
|
+
* import { AppComponent } from './app/app.component';
|
|
13
|
+
*
|
|
14
|
+
* wuAngular.register('my-app', AppModule);
|
|
15
|
+
* // o
|
|
16
|
+
* wuAngular.registerStandalone('my-app', AppComponent);
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Shell (cargar microfrontend)
|
|
20
|
+
* import { WuSlotComponent } from 'wu-framework/adapters/angular';
|
|
21
|
+
*
|
|
22
|
+
* <wu-slot name="my-app" url="http://localhost:3001"></wu-slot>
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Estado global del adapter
|
|
26
|
+
const adapterState = {
|
|
27
|
+
apps: new Map(),
|
|
28
|
+
platformRef: null,
|
|
29
|
+
initialized: false
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Obtiene la instancia de Wu Framework
|
|
34
|
+
*/
|
|
35
|
+
function getWuInstance() {
|
|
36
|
+
if (typeof window === 'undefined') return null;
|
|
37
|
+
|
|
38
|
+
return window.wu
|
|
39
|
+
|| window.parent?.wu
|
|
40
|
+
|| window.top?.wu
|
|
41
|
+
|| null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Espera a que Wu Framework esté disponible
|
|
46
|
+
*/
|
|
47
|
+
function waitForWu(timeout = 5000) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const wu = getWuInstance();
|
|
50
|
+
if (wu) {
|
|
51
|
+
resolve(wu);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
|
|
57
|
+
const handleWuReady = () => {
|
|
58
|
+
cleanup();
|
|
59
|
+
resolve(getWuInstance());
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
window.addEventListener('wu:ready', handleWuReady);
|
|
63
|
+
window.addEventListener('wu:app:ready', handleWuReady);
|
|
64
|
+
|
|
65
|
+
const checkInterval = setInterval(() => {
|
|
66
|
+
const wu = getWuInstance();
|
|
67
|
+
if (wu) {
|
|
68
|
+
cleanup();
|
|
69
|
+
resolve(wu);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (Date.now() - startTime > timeout) {
|
|
74
|
+
cleanup();
|
|
75
|
+
reject(new Error(`Wu Framework not found after ${timeout}ms`));
|
|
76
|
+
}
|
|
77
|
+
}, 200);
|
|
78
|
+
|
|
79
|
+
function cleanup() {
|
|
80
|
+
clearInterval(checkInterval);
|
|
81
|
+
window.removeEventListener('wu:ready', handleWuReady);
|
|
82
|
+
window.removeEventListener('wu:app:ready', handleWuReady);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Registra un módulo Angular como microfrontend
|
|
89
|
+
*
|
|
90
|
+
* @param {string} appName - Nombre único del microfrontend
|
|
91
|
+
* @param {Type<any>} AppModule - Módulo Angular principal (AppModule)
|
|
92
|
+
* @param {Object} options - Opciones adicionales
|
|
93
|
+
* @param {Function} options.platformFactory - Factory del platform (platformBrowserDynamic por defecto)
|
|
94
|
+
* @param {Array} options.providers - Providers adicionales para bootstrap
|
|
95
|
+
* @param {Function} options.onMount - Callback después de montar
|
|
96
|
+
* @param {Function} options.onUnmount - Callback antes de desmontar
|
|
97
|
+
* @param {boolean} options.standalone - Permitir ejecución standalone (default: true)
|
|
98
|
+
* @param {string} options.standaloneContainer - Selector para modo standalone (default: '#root')
|
|
99
|
+
* @param {string} options.rootSelector - Selector del componente root (default: 'app-root')
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* // Básico
|
|
103
|
+
* wuAngular.register('my-app', AppModule);
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* // Con opciones
|
|
107
|
+
* wuAngular.register('my-app', AppModule, {
|
|
108
|
+
* providers: [{ provide: 'API_URL', useValue: 'https://api.example.com' }],
|
|
109
|
+
* onMount: (container) => console.log('Mounted!'),
|
|
110
|
+
* rootSelector: 'my-app-root'
|
|
111
|
+
* });
|
|
112
|
+
*/
|
|
113
|
+
async function register(appName, AppModule, options = {}) {
|
|
114
|
+
const {
|
|
115
|
+
platformFactory = null,
|
|
116
|
+
providers = [],
|
|
117
|
+
onMount = null,
|
|
118
|
+
onUnmount = null,
|
|
119
|
+
standalone = true,
|
|
120
|
+
standaloneContainer = '#root',
|
|
121
|
+
rootSelector = 'app-root'
|
|
122
|
+
} = options;
|
|
123
|
+
|
|
124
|
+
// Función de mount interna
|
|
125
|
+
const mountApp = async (container) => {
|
|
126
|
+
if (!container) {
|
|
127
|
+
console.error(`[WuAngular] Mount failed for ${appName}: container is null`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Evitar doble mount
|
|
132
|
+
if (adapterState.apps.has(appName)) {
|
|
133
|
+
console.warn(`[WuAngular] ${appName} already mounted, unmounting first`);
|
|
134
|
+
await unmountApp();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// Crear elemento root para Angular
|
|
139
|
+
const appElement = document.createElement(rootSelector);
|
|
140
|
+
appElement.setAttribute('data-wu-angular-root', appName);
|
|
141
|
+
container.innerHTML = '';
|
|
142
|
+
container.appendChild(appElement);
|
|
143
|
+
|
|
144
|
+
// Obtener platformBrowserDynamic
|
|
145
|
+
let platform;
|
|
146
|
+
if (platformFactory) {
|
|
147
|
+
platform = platformFactory;
|
|
148
|
+
} else {
|
|
149
|
+
// Intentar import dinámico
|
|
150
|
+
try {
|
|
151
|
+
const platformModule = await import('@angular/platform-browser-dynamic');
|
|
152
|
+
platform = platformModule.platformBrowserDynamic;
|
|
153
|
+
} catch (e) {
|
|
154
|
+
// Intentar desde window
|
|
155
|
+
if (window.ng?.platformBrowserDynamic) {
|
|
156
|
+
platform = window.ng.platformBrowserDynamic;
|
|
157
|
+
} else {
|
|
158
|
+
throw new Error('platformBrowserDynamic not available. Please provide it via options.platformFactory');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Bootstrap del módulo
|
|
164
|
+
const platformRef = platform(providers);
|
|
165
|
+
const moduleRef = await platformRef.bootstrapModule(AppModule);
|
|
166
|
+
|
|
167
|
+
// Guardar referencias
|
|
168
|
+
adapterState.apps.set(appName, {
|
|
169
|
+
platformRef,
|
|
170
|
+
moduleRef,
|
|
171
|
+
container,
|
|
172
|
+
rootElement: appElement
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
console.log(`[WuAngular] ✅ ${appName} mounted successfully`);
|
|
176
|
+
|
|
177
|
+
if (onMount) {
|
|
178
|
+
onMount(container, moduleRef);
|
|
179
|
+
}
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error(`[WuAngular] Mount error for ${appName}:`, error);
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Función de unmount interna
|
|
187
|
+
const unmountApp = async (container) => {
|
|
188
|
+
const instance = adapterState.apps.get(appName);
|
|
189
|
+
|
|
190
|
+
if (instance) {
|
|
191
|
+
try {
|
|
192
|
+
if (onUnmount) {
|
|
193
|
+
onUnmount(instance.container, instance.moduleRef);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Destruir el módulo
|
|
197
|
+
if (instance.moduleRef) {
|
|
198
|
+
instance.moduleRef.destroy();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Destruir la plataforma
|
|
202
|
+
if (instance.platformRef) {
|
|
203
|
+
instance.platformRef.destroy();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Limpiar DOM
|
|
207
|
+
if (instance.rootElement && instance.rootElement.parentNode) {
|
|
208
|
+
instance.rootElement.parentNode.removeChild(instance.rootElement);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
adapterState.apps.delete(appName);
|
|
212
|
+
|
|
213
|
+
console.log(`[WuAngular] ✅ ${appName} unmounted successfully`);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.error(`[WuAngular] Unmount error for ${appName}:`, error);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Limpiar container si se proporciona
|
|
220
|
+
if (container) {
|
|
221
|
+
container.innerHTML = '';
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Intentar registrar con Wu Framework
|
|
226
|
+
try {
|
|
227
|
+
const wu = await waitForWu(3000);
|
|
228
|
+
|
|
229
|
+
wu.define(appName, {
|
|
230
|
+
mount: mountApp,
|
|
231
|
+
unmount: unmountApp
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
console.log(`[WuAngular] ✅ ${appName} registered with Wu Framework`);
|
|
235
|
+
return true;
|
|
236
|
+
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.warn(`[WuAngular] Wu Framework not available for ${appName}`);
|
|
239
|
+
|
|
240
|
+
// Modo standalone si está habilitado
|
|
241
|
+
if (standalone) {
|
|
242
|
+
const containerElement = document.querySelector(standaloneContainer);
|
|
243
|
+
|
|
244
|
+
if (containerElement) {
|
|
245
|
+
console.log(`[WuAngular] Running ${appName} in standalone mode`);
|
|
246
|
+
await mountApp(containerElement);
|
|
247
|
+
return true;
|
|
248
|
+
} else {
|
|
249
|
+
console.warn(`[WuAngular] Standalone container ${standaloneContainer} not found`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Registra un componente Angular standalone como microfrontend (Angular 14+)
|
|
259
|
+
*
|
|
260
|
+
* @param {string} appName - Nombre único del microfrontend
|
|
261
|
+
* @param {Type<any>} RootComponent - Componente standalone principal
|
|
262
|
+
* @param {Object} options - Opciones adicionales
|
|
263
|
+
* @param {ApplicationConfig} options.appConfig - Configuración de la aplicación
|
|
264
|
+
* @param {Function} options.onMount - Callback después de montar
|
|
265
|
+
* @param {Function} options.onUnmount - Callback antes de desmontar
|
|
266
|
+
* @param {boolean} options.standalone - Permitir ejecución standalone (default: true)
|
|
267
|
+
* @param {string} options.standaloneContainer - Selector para modo standalone (default: '#root')
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* // Angular 14+ con standalone components
|
|
271
|
+
* import { AppComponent } from './app/app.component';
|
|
272
|
+
* import { appConfig } from './app/app.config';
|
|
273
|
+
*
|
|
274
|
+
* wuAngular.registerStandalone('my-app', AppComponent, { appConfig });
|
|
275
|
+
*/
|
|
276
|
+
async function registerStandalone(appName, RootComponent, options = {}) {
|
|
277
|
+
const {
|
|
278
|
+
appConfig = {},
|
|
279
|
+
onMount = null,
|
|
280
|
+
onUnmount = null,
|
|
281
|
+
standalone = true,
|
|
282
|
+
standaloneContainer = '#root'
|
|
283
|
+
} = options;
|
|
284
|
+
|
|
285
|
+
// Función de mount para standalone components
|
|
286
|
+
const mountApp = async (container) => {
|
|
287
|
+
if (!container) {
|
|
288
|
+
console.error(`[WuAngular] Mount failed for ${appName}: container is null`);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Evitar doble mount
|
|
293
|
+
if (adapterState.apps.has(appName)) {
|
|
294
|
+
console.warn(`[WuAngular] ${appName} already mounted, unmounting first`);
|
|
295
|
+
await unmountApp();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
// Obtener bootstrapApplication
|
|
300
|
+
let bootstrapApplication;
|
|
301
|
+
try {
|
|
302
|
+
const browserModule = await import('@angular/platform-browser');
|
|
303
|
+
bootstrapApplication = browserModule.bootstrapApplication;
|
|
304
|
+
} catch (e) {
|
|
305
|
+
if (window.ng?.bootstrapApplication) {
|
|
306
|
+
bootstrapApplication = window.ng.bootstrapApplication;
|
|
307
|
+
} else {
|
|
308
|
+
throw new Error('bootstrapApplication not available. Requires Angular 14+');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Bootstrap del componente standalone
|
|
313
|
+
const appRef = await bootstrapApplication(RootComponent, appConfig);
|
|
314
|
+
|
|
315
|
+
// Guardar referencias
|
|
316
|
+
adapterState.apps.set(appName, {
|
|
317
|
+
appRef,
|
|
318
|
+
container,
|
|
319
|
+
isStandalone: true
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
console.log(`[WuAngular] ✅ ${appName} (standalone) mounted successfully`);
|
|
323
|
+
|
|
324
|
+
if (onMount) {
|
|
325
|
+
onMount(container, appRef);
|
|
326
|
+
}
|
|
327
|
+
} catch (error) {
|
|
328
|
+
console.error(`[WuAngular] Mount error for ${appName}:`, error);
|
|
329
|
+
throw error;
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// Función de unmount para standalone
|
|
334
|
+
const unmountApp = async (container) => {
|
|
335
|
+
const instance = adapterState.apps.get(appName);
|
|
336
|
+
|
|
337
|
+
if (instance) {
|
|
338
|
+
try {
|
|
339
|
+
if (onUnmount) {
|
|
340
|
+
onUnmount(instance.container, instance.appRef);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Destruir la aplicación
|
|
344
|
+
if (instance.appRef) {
|
|
345
|
+
instance.appRef.destroy();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
adapterState.apps.delete(appName);
|
|
349
|
+
|
|
350
|
+
console.log(`[WuAngular] ✅ ${appName} (standalone) unmounted successfully`);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
console.error(`[WuAngular] Unmount error for ${appName}:`, error);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (container) {
|
|
357
|
+
container.innerHTML = '';
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// Intentar registrar con Wu Framework
|
|
362
|
+
try {
|
|
363
|
+
const wu = await waitForWu(3000);
|
|
364
|
+
|
|
365
|
+
wu.define(appName, {
|
|
366
|
+
mount: mountApp,
|
|
367
|
+
unmount: unmountApp
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
console.log(`[WuAngular] ✅ ${appName} (standalone) registered with Wu Framework`);
|
|
371
|
+
return true;
|
|
372
|
+
|
|
373
|
+
} catch (error) {
|
|
374
|
+
console.warn(`[WuAngular] Wu Framework not available for ${appName}`);
|
|
375
|
+
|
|
376
|
+
if (standalone) {
|
|
377
|
+
const containerElement = document.querySelector(standaloneContainer);
|
|
378
|
+
|
|
379
|
+
if (containerElement) {
|
|
380
|
+
console.log(`[WuAngular] Running ${appName} in standalone mode`);
|
|
381
|
+
await mountApp(containerElement);
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Servicio Injectable para usar Wu Framework en Angular
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* // En tu módulo o componente
|
|
395
|
+
* import { WuService } from 'wu-framework/adapters/angular';
|
|
396
|
+
*
|
|
397
|
+
* @Injectable()
|
|
398
|
+
* export class MyService {
|
|
399
|
+
* constructor() {
|
|
400
|
+
* this.wu = createWuService();
|
|
401
|
+
* }
|
|
402
|
+
*
|
|
403
|
+
* sendEvent() {
|
|
404
|
+
* this.wu.emit('user:action', { data: 'test' });
|
|
405
|
+
* }
|
|
406
|
+
* }
|
|
407
|
+
*/
|
|
408
|
+
function createWuService() {
|
|
409
|
+
const subscriptions = [];
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
// Event Bus
|
|
413
|
+
emit: (event, data, options) => {
|
|
414
|
+
const wu = getWuInstance();
|
|
415
|
+
if (wu?.eventBus) {
|
|
416
|
+
wu.eventBus.emit(event, data, options);
|
|
417
|
+
} else {
|
|
418
|
+
console.warn('[WuService] Wu Framework not available');
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
|
|
422
|
+
on: (event, callback) => {
|
|
423
|
+
const wu = getWuInstance();
|
|
424
|
+
if (wu?.eventBus) {
|
|
425
|
+
const unsubscribe = wu.eventBus.on(event, callback);
|
|
426
|
+
subscriptions.push(unsubscribe);
|
|
427
|
+
return unsubscribe;
|
|
428
|
+
}
|
|
429
|
+
console.warn('[WuService] Wu Framework not available');
|
|
430
|
+
return () => {};
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
once: (event, callback) => {
|
|
434
|
+
const wu = getWuInstance();
|
|
435
|
+
if (wu?.eventBus) {
|
|
436
|
+
return wu.eventBus.once(event, callback);
|
|
437
|
+
}
|
|
438
|
+
return () => {};
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
off: (event, callback) => {
|
|
442
|
+
const wu = getWuInstance();
|
|
443
|
+
if (wu?.eventBus) {
|
|
444
|
+
wu.eventBus.off(event, callback);
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
// Store
|
|
449
|
+
getState: (path) => {
|
|
450
|
+
const wu = getWuInstance();
|
|
451
|
+
return wu?.store?.get(path) || null;
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
setState: (path, value) => {
|
|
455
|
+
const wu = getWuInstance();
|
|
456
|
+
if (wu?.store) {
|
|
457
|
+
wu.store.set(path, value);
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
|
|
461
|
+
onStateChange: (pattern, callback) => {
|
|
462
|
+
const wu = getWuInstance();
|
|
463
|
+
if (wu?.store) {
|
|
464
|
+
const unsubscribe = wu.store.on(pattern, callback);
|
|
465
|
+
subscriptions.push(unsubscribe);
|
|
466
|
+
return unsubscribe;
|
|
467
|
+
}
|
|
468
|
+
return () => {};
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
// Cleanup
|
|
472
|
+
destroy: () => {
|
|
473
|
+
subscriptions.forEach(unsub => unsub());
|
|
474
|
+
subscriptions.length = 0;
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
// Access to raw Wu instance
|
|
478
|
+
get wu() {
|
|
479
|
+
return getWuInstance();
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Crea un componente Angular para cargar microfrontends (para el Shell)
|
|
486
|
+
* Retorna la configuración del componente para ser usado con @Component
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* // wu-slot.component.ts
|
|
490
|
+
* import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
491
|
+
* import { createWuSlotComponent } from 'wu-framework/adapters/angular';
|
|
492
|
+
*
|
|
493
|
+
* const config = createWuSlotComponent();
|
|
494
|
+
*
|
|
495
|
+
* @Component({
|
|
496
|
+
* selector: 'wu-slot',
|
|
497
|
+
* template: config.template,
|
|
498
|
+
* styles: config.styles
|
|
499
|
+
* })
|
|
500
|
+
* export class WuSlotComponent {
|
|
501
|
+
* @Input() name!: string;
|
|
502
|
+
* @Input() url!: string;
|
|
503
|
+
* @Output() load = new EventEmitter();
|
|
504
|
+
* @Output() error = new EventEmitter();
|
|
505
|
+
*
|
|
506
|
+
* // ... implement lifecycle methods from config.methods
|
|
507
|
+
* }
|
|
508
|
+
*/
|
|
509
|
+
function createWuSlotComponent() {
|
|
510
|
+
return {
|
|
511
|
+
selector: 'wu-slot',
|
|
512
|
+
|
|
513
|
+
template: `
|
|
514
|
+
<div
|
|
515
|
+
#container
|
|
516
|
+
class="wu-slot"
|
|
517
|
+
[class.wu-slot-loading]="loading"
|
|
518
|
+
[class.wu-slot-error]="error"
|
|
519
|
+
[attr.data-wu-app]="name"
|
|
520
|
+
[attr.data-wu-url]="url"
|
|
521
|
+
style="min-height: 100px; position: relative;">
|
|
522
|
+
|
|
523
|
+
<div *ngIf="error" class="wu-slot-error-message"
|
|
524
|
+
style="padding: 1rem; border: 1px solid #f5c6cb; border-radius: 4px; background: #f8d7da; color: #721c24;">
|
|
525
|
+
<strong>Error loading {{ name }}</strong>
|
|
526
|
+
<p style="margin: 0.5rem 0 0 0;">{{ error }}</p>
|
|
527
|
+
</div>
|
|
528
|
+
|
|
529
|
+
<div *ngIf="loading && !error" class="wu-slot-loading-message"
|
|
530
|
+
style="display: flex; align-items: center; justify-content: center; padding: 2rem; color: #666;">
|
|
531
|
+
{{ fallbackText || 'Loading ' + name + '...' }}
|
|
532
|
+
</div>
|
|
533
|
+
</div>
|
|
534
|
+
`,
|
|
535
|
+
|
|
536
|
+
styles: [`
|
|
537
|
+
.wu-slot {
|
|
538
|
+
width: 100%;
|
|
539
|
+
min-height: 100px;
|
|
540
|
+
}
|
|
541
|
+
`],
|
|
542
|
+
|
|
543
|
+
// Métodos para implementar en el componente
|
|
544
|
+
methods: {
|
|
545
|
+
async ngOnInit() {
|
|
546
|
+
await this.mountMicrofrontend();
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
ngOnDestroy() {
|
|
550
|
+
this.unmountMicrofrontend();
|
|
551
|
+
},
|
|
552
|
+
|
|
553
|
+
async mountMicrofrontend() {
|
|
554
|
+
try {
|
|
555
|
+
this.loading = true;
|
|
556
|
+
this.error = null;
|
|
557
|
+
|
|
558
|
+
const wu = getWuInstance();
|
|
559
|
+
if (!wu) {
|
|
560
|
+
throw new Error('Wu Framework not initialized');
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Crear container único
|
|
564
|
+
const containerId = `wu-slot-${this.name}-${Date.now()}`;
|
|
565
|
+
const innerContainer = document.createElement('div');
|
|
566
|
+
innerContainer.id = containerId;
|
|
567
|
+
innerContainer.style.width = '100%';
|
|
568
|
+
innerContainer.style.height = '100%';
|
|
569
|
+
|
|
570
|
+
this.container.nativeElement.innerHTML = '';
|
|
571
|
+
this.container.nativeElement.appendChild(innerContainer);
|
|
572
|
+
|
|
573
|
+
// Crear y montar la app
|
|
574
|
+
const app = wu.app(this.name, {
|
|
575
|
+
url: this.url,
|
|
576
|
+
container: `#${containerId}`,
|
|
577
|
+
autoInit: true
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
this.appInstance = app;
|
|
581
|
+
await app.mount();
|
|
582
|
+
|
|
583
|
+
this.loading = false;
|
|
584
|
+
this.load.emit({ name: this.name, url: this.url });
|
|
585
|
+
|
|
586
|
+
} catch (err) {
|
|
587
|
+
console.error(`[WuSlot] Error loading ${this.name}:`, err);
|
|
588
|
+
this.error = err.message || 'Failed to load microfrontend';
|
|
589
|
+
this.loading = false;
|
|
590
|
+
this.errorEvent.emit(err);
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
|
|
594
|
+
async unmountMicrofrontend() {
|
|
595
|
+
if (this.appInstance) {
|
|
596
|
+
try {
|
|
597
|
+
await this.appInstance.unmount();
|
|
598
|
+
} catch (err) {
|
|
599
|
+
console.warn(`[WuSlot] Error unmounting ${this.name}:`, err);
|
|
600
|
+
}
|
|
601
|
+
this.appInstance = null;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Helper para crear un módulo Angular que exporta WuSlotComponent
|
|
610
|
+
* Útil para shells que quieren usar <wu-slot> directamente
|
|
611
|
+
*/
|
|
612
|
+
function getWuSlotModuleConfig() {
|
|
613
|
+
return {
|
|
614
|
+
imports: ['CommonModule'],
|
|
615
|
+
declarations: ['WuSlotComponent'],
|
|
616
|
+
exports: ['WuSlotComponent']
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// API pública del adapter
|
|
621
|
+
export const wuAngular = {
|
|
622
|
+
register,
|
|
623
|
+
registerStandalone,
|
|
624
|
+
createWuService,
|
|
625
|
+
createWuSlotComponent,
|
|
626
|
+
getWuSlotModuleConfig,
|
|
627
|
+
getWuInstance,
|
|
628
|
+
waitForWu
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
// Named exports para conveniencia
|
|
632
|
+
export {
|
|
633
|
+
register,
|
|
634
|
+
registerStandalone,
|
|
635
|
+
createWuService,
|
|
636
|
+
createWuSlotComponent,
|
|
637
|
+
getWuSlotModuleConfig,
|
|
638
|
+
getWuInstance,
|
|
639
|
+
waitForWu
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
export default wuAngular;
|