wu-framework 1.1.4 β†’ 1.1.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.
package/README.md CHANGED
@@ -1,553 +1,1273 @@
1
- # πŸš€ Wu Framework
1
+ # Wu Framework
2
2
 
3
3
  **Universal Microfrontends Made Simple**
4
4
 
5
- Wu Framework es una librerΓ­a de microfrontends con **Shadow DOM nativo**, **aislamiento CSS avanzado**, y **comunicaciΓ³n cross-MFE** integrada.
5
+ Wu Framework es la libreria de microfrontends mas simple y poderosa del mercado. Framework agnostic, zero config, Shadow DOM nativo.
6
+
7
+ ## Por que Wu Framework?
8
+
9
+ | Caracteristica | Module Federation | qiankun | single-spa | **Wu Framework** |
10
+ |---|---|---|---|---|
11
+ | **Setup** | Webpack config complejo | Configuracion manual | Config extensa | **Zero config** |
12
+ | **Framework Support** | React-first | Multi framework | Multi framework | **8 frameworks nativos** |
13
+ | **Bundler Required** | Solo Webpack 5 | Agnostico | Agnostico | **Ninguno requerido** |
14
+ | **CSS Isolation** | Basico | CSS hacks | Manual | **Shadow DOM nativo** |
15
+ | **JS Isolation** | No | Proxy basico | No | **Proxy + Snapshot Sandbox** |
16
+ | **Style Modes** | No | No | No | **3 modos (shared/isolated/fully-isolated)** |
17
+ | **Runtime Config** | No | Limitado | Limitado | **Completamente dinamico** |
18
+ | **Self-Healing** | No | No | No | **Auto-recovery** |
19
+ | **Build Protection** | No | No | No | **Minify + Obfuscate + Base64** |
20
+ | **API Complexity** | Alta | Media | Alta | **1 linea de codigo** |
21
+
22
+ ## Instalacion
23
+
24
+ ```bash
25
+ npm install wu-framework
26
+ ```
27
+
28
+ Sin webpack config, sin plugins, sin configuracion adicional.
6
29
 
7
30
  ---
8
31
 
9
- ## ✨ ¿Por qué Wu Framework?
32
+ ## Frameworks Soportados
10
33
 
11
- | CaracterΓ­stica | Module Federation | Single-SPA | Qiankun | **Wu Framework** |
12
- |---|---|---|---|---|
13
- | **Shadow DOM nativo** | ❌ | ❌ | Parcial | **βœ… Completo** |
14
- | **CSS Isolation Modes** | Manual | Manual | BΓ‘sico | **βœ… 4 modos** |
15
- | **`fully-isolated` mode** | ❌ | ❌ | ❌ | **βœ… Único** |
16
- | **Bloquea CSS Variables** | ❌ | ❌ | ❌ | **βœ… Único** |
17
- | **Framework Agnostic** | Webpack only | βœ… | Vue-first | **βœ… Cualquiera** |
18
- | **Bundler Agnostic** | Webpack 5 | βœ… | Webpack | **βœ… Vite/Webpack** |
19
- | **Cross-MFE Events** | Manual | Manual | Props | **βœ… Event Bus** |
20
- | **Cross-MFE Store** | ❌ | ❌ | Parcial | **βœ… Reactive Store** |
34
+ Wu Framework incluye **adapters nativos** para los frameworks mas populares:
35
+
36
+ | Framework | Adapter | Registro |
37
+ |-----------|---------|----------|
38
+ | React | `wuReact` | `wuReact.register('app', App)` |
39
+ | Vue | `wuVue` | `wuVue.register('app', App)` |
40
+ | Angular | `wuAngular` | `wuAngular.register('app', AppModule)` |
41
+ | Angular Standalone | `wuAngular` | `wuAngular.registerStandalone('app', Component)` |
42
+ | Angular Elements | `wuAngular` | `wuAngular.registerElement('app', Component)` |
43
+ | Svelte | `wuSvelte` | `wuSvelte.register('app', App)` |
44
+ | Preact | `wuPreact` | `wuPreact.register('app', App)` |
45
+ | Solid.js | `wuSolid` | `wuSolid.register('app', App)` |
46
+ | Lit | `wuLit` | `wuLit.register('app', MyElement)` |
47
+ | Vanilla JS | `wuVanilla` | `wuVanilla.register('app', config)` |
21
48
 
22
49
  ---
23
50
 
24
- ## πŸ›‘οΈ CSS Isolation Modes (Feature Único)
51
+ ## Quick Start
52
+
53
+ ### 1. Micro App: Crear `wu.json`
25
54
 
26
- Wu Framework ofrece **4 modos de aislamiento CSS**. El modo `fully-isolated` es **ΓΊnico** - bloquea incluso las CSS variables del padre:
55
+ Cada microfrontend necesita un archivo `wu.json` en su raiz:
27
56
 
28
57
  ```json
29
- // header/wu.json - Aislamiento total (bloquea CSS vars del padre)
30
58
  {
31
59
  "name": "header",
32
- "entry": "src/main.ts",
33
- "styleMode": "fully-isolated",
60
+ "version": "1.0.0",
61
+ "entry": "index.js",
62
+ "styleMode": "shared",
34
63
  "wu": {
64
+ "exports": {
65
+ "NavBar": "components/NavBar.js",
66
+ "UserMenu": "components/UserMenu.js"
67
+ },
68
+ "imports": [],
69
+ "routes": ["/", "/home"],
35
70
  "permissions": ["events", "store"]
36
71
  }
37
72
  }
38
73
  ```
39
74
 
75
+ | Campo | Descripcion |
76
+ |-------|-------------|
77
+ | `name` | Nombre unico del microfrontend |
78
+ | `version` | Version del microfrontend |
79
+ | `entry` | Archivo JS principal (default: `index.js`) |
80
+ | `styleMode` | Modo de estilos: `shared`, `isolated`, `fully-isolated` |
81
+ | `wu.exports` | Componentes que expone a otros microfrontends |
82
+ | `wu.imports` | Componentes que importa de otros microfrontends |
83
+ | `wu.routes` | Rutas que maneja este microfrontend |
84
+ | `wu.permissions` | Permisos requeridos (`events`, `store`, `dom`) |
85
+
86
+ ### 2. Micro App: Registrar con Adapter (1 linea)
87
+
88
+ **React:**
89
+ ```tsx
90
+ import { wuReact } from 'wu-framework/adapters/react';
91
+ import App from './App';
92
+
93
+ wuReact.register('header', App);
94
+ ```
95
+
96
+ **Vue:**
97
+ ```ts
98
+ import { wuVue } from 'wu-framework/adapters/vue';
99
+ import App from './App.vue';
100
+
101
+ wuVue.register('sidebar', App);
102
+ ```
103
+
104
+ **Angular:**
105
+ ```ts
106
+ import { wuAngular } from 'wu-framework/adapters/angular';
107
+ import { AppModule } from './app/app.module';
108
+
109
+ wuAngular.register('content', AppModule);
110
+ ```
111
+
112
+ El adapter se encarga de todo: deteccion de contexto, modo standalone, cleanup automatico.
113
+
114
+ ### 3. Shell (Host Application)
115
+
116
+ **Desarrollo:**
117
+ ```js
118
+ import { wu } from 'wu-framework';
119
+
120
+ await wu.init({
121
+ apps: [
122
+ { name: 'header', url: 'http://localhost:3001' },
123
+ { name: 'sidebar', url: 'http://localhost:3002' },
124
+ { name: 'content', url: 'http://localhost:3003' }
125
+ ]
126
+ });
127
+
128
+ await wu.mount('header', '#header-container');
129
+ await wu.mount('sidebar', '#sidebar-container');
130
+ await wu.mount('content', '#content-container');
131
+ ```
132
+
133
+ **Produccion:**
134
+ ```js
135
+ import { wu } from 'wu-framework';
136
+
137
+ await wu.init({
138
+ apps: [
139
+ { name: 'header', url: 'https://cdn.mycompany.com/mfe/header' },
140
+ { name: 'sidebar', url: 'https://cdn.mycompany.com/mfe/sidebar' },
141
+ { name: 'content', url: 'https://cdn.mycompany.com/mfe/content' }
142
+ ]
143
+ });
144
+ ```
145
+
146
+ ### Estructura de Archivos (Microfrontend)
147
+
148
+ ```
149
+ my-header-mfe/
150
+ β”œβ”€β”€ wu.json # Manifest requerido
151
+ β”œβ”€β”€ index.js # Entry point (registra con adapter)
152
+ β”œβ”€β”€ App.jsx # Componente principal
153
+ β”œβ”€β”€ components/
154
+ β”‚ β”œβ”€β”€ NavBar.js
155
+ β”‚ └── UserMenu.js
156
+ └── package.json
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Modos de Inyeccion de Estilos
162
+
163
+ Wu Framework soporta **3 modos de inyeccion de estilos** en Shadow DOM:
164
+
165
+ | Modo | Descripcion | Riesgo Colision |
166
+ |------|-------------|-----------------|
167
+ | `shared` | Inyecta TODOS los estilos del documento padre | Alto |
168
+ | `isolated` | NO inyecta estilos externos (Shadow DOM nativo) | Ninguno |
169
+ | `fully-isolated` | Inyecta SOLO estilos propios de la app | Ninguno |
170
+
171
+ ### Configuracion en wu.json
172
+
40
173
  ```json
41
- // container/wu.json - Aislamiento normal (hereda CSS vars)
42
174
  {
43
- "name": "content",
44
- "folder": "container",
45
- "entry": "src/main.tsx",
46
- "styleMode": "isolated",
47
- "wu": {
48
- "permissions": ["events", "store"]
49
- }
175
+ "name": "my-app",
176
+ "styleMode": "isolated"
50
177
  }
51
178
  ```
52
179
 
53
- | Modo | CSS Variables | Estilos Padre | Caso de Uso |
54
- |------|--------------|---------------|-------------|
55
- | `isolated` | βœ… Heredadas | ❌ Bloqueados | MFE usa design system del host |
56
- | `fully-isolated` | ❌ **Bloqueadas** | ❌ Bloqueados | MFE de terceros con su propio theme |
57
- | `shared` | βœ… Heredadas | βœ… Compartidos | MFE necesita estilos del host |
58
- | `auto` | βœ… Heredadas | ⚑ Solo librerΓ­as | Compartir Element Plus, etc. |
180
+ ### shared (default)
181
+
182
+ - Inyecta estilos de librerias (Element Plus, Tailwind, Vue Flow, etc.)
183
+ - Inyecta estilos globales del documento
184
+ - Observer HMR para cambios en desarrollo
185
+ - **Ideal para:** Apps que comparten un design system comun
186
+
187
+ ### isolated
188
+
189
+ - NO inyecta ningun estilo externo
190
+ - Usa encapsulamiento nativo del Shadow DOM
191
+ - La app debe incluir sus propios estilos (CSS-in-JS, scoped, imports)
192
+ - **Ideal para:** Apps con estilos completamente independientes
193
+
194
+ ### fully-isolated
195
+
196
+ - Detecta y inyecta SOLO estilos propios de la app especifica
197
+ - Patron de deteccion: `packages/appName/src/`
198
+ - MutationObserver persistente para HMR de Vite
199
+ - **Ideal para:** Apps que necesitan sus estilos pero no los globales
59
200
 
60
201
  ---
61
202
 
62
- ## πŸ”₯ Quick Start
203
+ ## React Adapter
63
204
 
64
- ### 1. Shell (React + Vite)
205
+ ### Registro Basico
65
206
 
66
207
  ```tsx
67
- // shell/src/config/mfe.config.ts
68
- const isDev = import.meta.env.DEV
69
-
70
- const devUrls = {
71
- header: 'http://localhost:3001',
72
- content: 'http://localhost:3003'
73
- }
208
+ import { wuReact } from 'wu-framework/adapters/react';
209
+ import App from './App';
74
210
 
75
- const prodUrls = {
76
- header: import.meta.env.VITE_HEADER_URL || 'https://cdn.example.com/mfe/header',
77
- content: import.meta.env.VITE_CONTENT_URL || 'https://cdn.example.com/mfe/content'
78
- }
211
+ wuReact.register('my-app', App);
212
+ ```
79
213
 
80
- export const urls = isDev ? devUrls : prodUrls
214
+ ### Con Opciones
81
215
 
82
- export const enabledApps = [
83
- { name: 'header', url: urls.header, enabled: true },
84
- { name: 'content', url: urls.content, enabled: true }
85
- ]
216
+ ```tsx
217
+ wuReact.register('my-app', App, {
218
+ strictMode: true, // Envolver en React.StrictMode
219
+ props: { theme: 'dark' }, // Props iniciales
220
+ standalone: true, // Ejecutar independiente si Wu no esta
221
+ standaloneContainer: '#root',
222
+ onMount: (container) => console.log('Mounted!'),
223
+ onUnmount: (container) => console.log('Unmounted!')
224
+ });
86
225
  ```
87
226
 
227
+ ### Hooks para React
228
+
88
229
  ```tsx
89
- // shell/src/hooks/useWuFramework.ts
90
- import { useEffect, useState, useRef } from 'react'
91
- import { wu } from 'wu-framework'
92
- import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/react'
93
- import React from 'react'
94
- import { enabledApps } from '../config/mfe.config'
95
-
96
- // Crear hooks reactivos para el shell
97
- export const useWuEvents = createUseWuEvents(React)
98
- export const useWuStore = createUseWuStore(React)
99
-
100
- export function useWuFramework() {
101
- const [state, setState] = useState({
102
- initialized: false,
103
- loading: true,
104
- error: null as Error | null
105
- })
106
- const initRef = useRef(false)
230
+ import React from 'react';
231
+ import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/react';
107
232
 
108
- useEffect(() => {
109
- if (initRef.current) return
110
- initRef.current = true
111
-
112
- const initWu = async () => {
113
- try {
114
- await wu.init({
115
- apps: enabledApps.map(({ name, url }) => ({ name, url }))
116
- })
117
- setState({ initialized: true, loading: false, error: null })
118
- } catch (error) {
119
- setState({ initialized: false, loading: false, error: error as Error })
120
- }
121
- }
233
+ const useWuEvents = createUseWuEvents(React);
234
+ const useWuStore = createUseWuStore(React);
235
+
236
+ function MyComponent() {
237
+ const { emit, on } = useWuEvents();
238
+ const { state, setState } = useWuStore('user');
122
239
 
123
- initWu()
124
- }, [])
240
+ useEffect(() => {
241
+ const unsub = on('cart:updated', (data) => {
242
+ console.log('Cart updated:', data);
243
+ });
244
+ return unsub;
245
+ }, [on]);
125
246
 
126
- return { ...state, wu }
247
+ return (
248
+ <button onClick={() => emit('user:logout')}>
249
+ Logout {state?.name}
250
+ </button>
251
+ );
127
252
  }
128
253
  ```
129
254
 
130
- ```tsx
131
- // shell/src/App.tsx
132
- import { useWuFramework, useWuEvents } from './hooks/useWuFramework'
133
- import WuSlot from './components/WuSlot'
134
- import ToastContainer from './components/ToastContainer'
255
+ ### Cargar Microfrontends en React (Shell)
135
256
 
136
- function App() {
137
- const { initialized, loading, error } = useWuFramework()
138
- const { emit } = useWuEvents()
257
+ ```tsx
258
+ import React from 'react';
259
+ import { createWuSlot } from 'wu-framework/adapters/react';
139
260
 
140
- useEffect(() => {
141
- if (initialized) {
142
- emit('shell:ready', { timestamp: Date.now() })
143
- }
144
- }, [initialized, emit])
261
+ const WuSlot = createWuSlot(React);
145
262
 
146
- if (loading) return <div>Loading Wu Framework...</div>
147
- if (error) return <div>Error: {error.message}</div>
263
+ const HEADER_URL = process.env.REACT_APP_HEADER_URL || 'http://localhost:3001';
148
264
 
265
+ function Shell() {
149
266
  return (
150
- <>
151
- <ToastContainer />
152
- <WuSlot name="header" url={urls.header} />
153
- <WuSlot name="content" url={urls.content} />
154
- </>
155
- )
267
+ <div>
268
+ <WuSlot
269
+ name="header"
270
+ url={HEADER_URL}
271
+ onLoad={() => console.log('Header loaded!')}
272
+ onError={(err) => console.error(err)}
273
+ />
274
+ </div>
275
+ );
156
276
  }
157
277
  ```
158
278
 
159
- ### 2. MFE Header (Vue 3)
279
+ ---
160
280
 
161
- ```json
162
- // header/wu.json
163
- {
164
- "name": "header",
165
- "entry": "src/main.ts",
166
- "styleMode": "fully-isolated",
167
- "wu": {
168
- "exports": {
169
- "NavBar": "src/components/NavBar.vue"
170
- },
171
- "permissions": ["events", "store"]
172
- }
173
- }
281
+ ## Vue Adapter
282
+
283
+ ### Registro Basico
284
+
285
+ ```ts
286
+ import { wuVue } from 'wu-framework/adapters/vue';
287
+ import App from './App.vue';
288
+
289
+ wuVue.register('my-app', App);
174
290
  ```
175
291
 
292
+ ### Con Plugins (Pinia, Router, etc.)
293
+
176
294
  ```ts
177
- // header/src/main.ts
178
- import { createApp } from 'vue'
179
- import { wuVue } from 'wu-framework/adapters/vue'
180
- import App from './App.vue'
181
-
182
- // Registrar con Wu Framework
183
- wuVue.register('header', App, {
184
- standalone: true,
185
- standaloneContainer: '#app',
186
- onMount: (container) => console.log('[Header] Mounted:', container),
187
- onUnmount: (container) => console.log('[Header] Unmounted:', container)
188
- })
295
+ import { wuVue } from 'wu-framework/adapters/vue';
296
+ import { createPinia } from 'pinia';
297
+ import router from './router';
298
+ import App from './App.vue';
299
+
300
+ wuVue.register('my-app', App, {
301
+ setup: (app) => {
302
+ app.use(createPinia());
303
+ app.use(router);
304
+ }
305
+ });
189
306
  ```
190
307
 
191
- ```vue
192
- <!-- header/src/components/NavBar.vue -->
193
- <script setup lang="ts">
194
- import { ref, onMounted, onUnmounted } from 'vue'
195
- import { useWuEvents, useWuStore } from 'wu-framework/adapters/vue'
308
+ ### Composables para Vue
196
309
 
197
- const { emit, on } = useWuEvents()
198
- const { state: notificationState, setState } = useWuStore('notifications')
310
+ ```vue
311
+ <script setup>
312
+ import { onMounted, onUnmounted } from 'vue';
313
+ import { useWuEvents, useWuStore } from 'wu-framework/adapters/vue';
199
314
 
200
- const notificationCount = ref(0)
201
- let unsubscribe: (() => void) | null = null
315
+ const { emit, on, cleanup } = useWuEvents();
316
+ const { state, setState } = useWuStore('cart');
202
317
 
203
318
  onMounted(() => {
204
- // Inicializar store compartido
205
- if (!notificationState.value) {
206
- setState({ count: 0, items: [] })
207
- }
319
+ on('user:login', (data) => console.log('Login:', data));
320
+ });
208
321
 
209
- // Escuchar notificaciones desde CUALQUIER MFE (React, Angular, etc.)
210
- unsubscribe = on('notification:new', (event) => {
211
- notificationCount.value++
212
-
213
- // Actualizar store compartido
214
- const current = notificationState.value || { count: 0, items: [] }
215
- setState({
216
- count: current.count + 1,
217
- items: [...current.items, {
218
- id: Date.now(),
219
- message: event.data?.message,
220
- type: event.data?.type || 'info'
221
- }]
222
- })
223
- })
224
- })
322
+ onUnmounted(() => cleanup());
323
+ </script>
225
324
 
226
- onUnmounted(() => {
227
- if (unsubscribe) unsubscribe()
228
- })
325
+ <template>
326
+ <div>
327
+ <p>Items: {{ state?.items?.length }}</p>
328
+ <button @click="emit('cart:clear')">Clear Cart</button>
329
+ </div>
330
+ </template>
331
+ ```
229
332
 
230
- const handleNavClick = (item: { id: string, label: string }) => {
231
- emit('header:nav:click', { id: item.id, label: item.label })
232
- }
333
+ ### Cargar Microfrontends en Vue (Shell)
334
+
335
+ ```vue
336
+ <script setup>
337
+ import { WuSlot } from 'wu-framework/adapters/vue';
338
+
339
+ const headerUrl = import.meta.env.VITE_HEADER_URL || 'http://localhost:3001';
233
340
  </script>
234
341
 
235
342
  <template>
236
- <nav class="navbar">
237
- <button class="navbar__notifications" @click="emit('header:notifications:open')">
238
- πŸ””
239
- <span v-if="notificationCount > 0" class="navbar__badge">
240
- {{ notificationCount > 99 ? '99+' : notificationCount }}
241
- </span>
242
- </button>
243
- </nav>
343
+ <div>
344
+ <WuSlot
345
+ name="header"
346
+ :url="headerUrl"
347
+ @load="onLoad"
348
+ @error="onError"
349
+ />
350
+ </div>
244
351
  </template>
245
352
  ```
246
353
 
247
- ### 3. MFE Content (React)
354
+ ### Plugin Global
248
355
 
249
- ```json
250
- // container/wu.json
251
- {
252
- "name": "content",
253
- "folder": "container",
254
- "entry": "src/main.tsx",
255
- "styleMode": "isolated",
256
- "wu": {
257
- "exports": {
258
- "Dashboard": "src/components/Dashboard.tsx"
259
- },
260
- "permissions": ["events", "store"]
356
+ ```ts
357
+ import { createApp } from 'vue';
358
+ import { wuVuePlugin } from 'wu-framework/adapters/vue';
359
+
360
+ const app = createApp(App);
361
+ app.use(wuVuePlugin); // Registra <WuSlot> globalmente
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Angular Adapter
367
+
368
+ ### Registro con NgModule
369
+
370
+ ```ts
371
+ import { wuAngular } from 'wu-framework/adapters/angular';
372
+ import { AppModule } from './app/app.module';
373
+
374
+ wuAngular.register('my-app', AppModule);
375
+ ```
376
+
377
+ ### Registro con Standalone Components (Angular 14+)
378
+
379
+ ```ts
380
+ import { wuAngular } from 'wu-framework/adapters/angular';
381
+ import { AppComponent } from './app/app.component';
382
+ import { appConfig } from './app/app.config';
383
+
384
+ wuAngular.registerStandalone('my-app', AppComponent, {
385
+ appConfig
386
+ });
387
+ ```
388
+
389
+ ### Registro con Angular Elements (Web Components)
390
+
391
+ Para proyectos que usan Angular Elements para crear Web Components:
392
+
393
+ ```ts
394
+ import { wuAngular } from 'wu-framework/adapters/angular';
395
+ import { AppComponent } from './app/app.component';
396
+ import { appConfig } from './app/app.config';
397
+
398
+ wuAngular.registerElement('my-app', AppComponent, {
399
+ elementTag: 'my-app-element', // Tag del custom element
400
+ appConfig, // Configuracion de Angular
401
+ standaloneContainer: '#root', // Container para modo standalone
402
+ onMount: (container, element) => {
403
+ console.log('Angular Element mounted');
404
+ },
405
+ onUnmount: (container, element) => {
406
+ console.log('Angular Element unmounted');
261
407
  }
262
- }
408
+ });
263
409
  ```
264
410
 
265
- ```tsx
266
- // container/src/main.tsx
267
- import { wuReact } from 'wu-framework/adapters/react'
268
- import App from './App'
411
+ El adapter se encarga de:
412
+ - Crear la aplicacion Angular
413
+ - Registrar el Custom Element con `customElements.define()`
414
+ - Gestionar el ciclo de vida mount/unmount
415
+ - Soportar modo standalone si Wu Framework no esta disponible
269
416
 
270
- wuReact.register('content', App, {
271
- strictMode: true,
272
- standalone: true,
273
- standaloneContainer: '#root',
274
- onMount: (container) => console.log('[Content] Mounted:', container),
275
- onUnmount: (container) => console.log('[Content] Unmounted:', container)
417
+ ### Servicio para Componentes
418
+
419
+ ```ts
420
+ import { Component, OnInit, OnDestroy } from '@angular/core';
421
+ import { createWuService } from 'wu-framework/adapters/angular';
422
+
423
+ @Component({
424
+ selector: 'app-root',
425
+ template: `<button (click)="sendEvent()">Send Event</button>`
276
426
  })
277
- ```
427
+ export class AppComponent implements OnInit, OnDestroy {
428
+ private wuService = createWuService();
278
429
 
279
- ```tsx
280
- // container/src/components/Dashboard.tsx
281
- import { useState } from 'react'
282
- import { useWuEvents } from '../hooks/useWu'
283
-
284
- export function Dashboard() {
285
- const { emit } = useWuEvents()
286
- const [sent, setSent] = useState(0)
287
-
288
- // Enviar notificaciΓ³n que el Header (Vue) y Shell (React) recibirΓ‘n
289
- const sendNotification = (type: 'success' | 'warning' | 'error' | 'info', message: string) => {
290
- emit('notification:new', { message, type })
291
- setSent(prev => prev + 1)
430
+ ngOnInit() {
431
+ this.wuService.on('user:login', (data) => {
432
+ console.log('User logged in:', data);
433
+ });
292
434
  }
293
435
 
294
- return (
295
- <div className="dashboard">
296
- <h2>Cross-MFE Communication Demo</h2>
297
- <p>Notifications sent: <strong>{sent}</strong></p>
298
-
299
- <div className="notification-buttons">
300
- <button onClick={() => sendNotification('success', 'Operation completed!')}>
301
- βœ… Success
302
- </button>
303
- <button onClick={() => sendNotification('warning', 'Check your settings')}>
304
- ⚠️ Warning
305
- </button>
306
- <button onClick={() => sendNotification('error', 'Something went wrong!')}>
307
- ❌ Error
308
- </button>
309
- <button onClick={() => sendNotification('info', 'New message received')}>
310
- πŸ’¬ Info
311
- </button>
312
- </div>
313
- </div>
314
- )
436
+ sendEvent() {
437
+ this.wuService.emit('app:ready', { timestamp: Date.now() });
438
+ }
439
+
440
+ ngOnDestroy() {
441
+ this.wuService.destroy();
442
+ }
315
443
  }
316
444
  ```
317
445
 
318
- ### 4. Toast Container (Shell - escucha eventos de MFEs)
446
+ ---
319
447
 
320
- ```tsx
321
- // shell/src/components/ToastContainer.tsx
322
- import { useState, useEffect, useCallback } from 'react'
323
- import { useWuEvents } from '../hooks/useWuFramework'
324
-
325
- interface Toast {
326
- id: string
327
- message: string
328
- type: 'success' | 'warning' | 'error' | 'info'
448
+ ## Svelte Adapter
449
+
450
+ ### Registro Basico
451
+
452
+ ```js
453
+ import { wuSvelte } from 'wu-framework/adapters/svelte';
454
+ import App from './App.svelte';
455
+
456
+ wuSvelte.register('my-app', App);
457
+ ```
458
+
459
+ ### Svelte 5 (con runes)
460
+
461
+ ```js
462
+ import { wuSvelte } from 'wu-framework/adapters/svelte';
463
+ import App from './App.svelte';
464
+
465
+ wuSvelte.registerSvelte5('my-app', App);
466
+ ```
467
+
468
+ ### Stores Reactivos
469
+
470
+ ```svelte
471
+ <script>
472
+ import { createWuStore, useWuEvents } from 'wu-framework/adapters/svelte';
473
+ import { onDestroy } from 'svelte';
474
+
475
+ const userStore = createWuStore('user');
476
+ const { emit, on, cleanup } = useWuEvents();
477
+
478
+ on('cart:updated', (data) => {
479
+ console.log('Cart updated:', data);
480
+ });
481
+
482
+ onDestroy(cleanup);
483
+ </script>
484
+
485
+ <p>Hello, {$userStore?.name}</p>
486
+ <button on:click={() => emit('user:logout')}>Logout</button>
487
+ ```
488
+
489
+ ---
490
+
491
+ ## Preact Adapter
492
+
493
+ ### Registro Basico
494
+
495
+ ```jsx
496
+ import { wuPreact } from 'wu-framework/adapters/preact';
497
+ import App from './App';
498
+
499
+ wuPreact.register('my-app', App);
500
+ ```
501
+
502
+ ### Compatible con React (preact/compat)
503
+
504
+ ```jsx
505
+ import { wuPreact } from 'wu-framework/adapters/preact';
506
+ import App from './App';
507
+
508
+ wuPreact.registerCompat('my-app', App);
509
+ ```
510
+
511
+ ### Hooks
512
+
513
+ ```jsx
514
+ import { h } from 'preact';
515
+ import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
516
+ import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/preact';
517
+
518
+ const useWuEvents = createUseWuEvents({ useCallback, useEffect, useRef });
519
+ const useWuStore = createUseWuStore({ useState, useCallback, useEffect });
520
+
521
+ function MyComponent() {
522
+ const { emit, on } = useWuEvents();
523
+ const { state } = useWuStore('user');
524
+
525
+ return <div>Hello {state?.name}</div>;
329
526
  }
527
+ ```
528
+
529
+ ---
330
530
 
331
- export function ToastContainer() {
332
- const [toasts, setToasts] = useState<Toast[]>([])
333
- const { on } = useWuEvents()
531
+ ## Solid.js Adapter
334
532
 
335
- const addToast = useCallback((message: string, type: Toast['type']) => {
336
- const id = `toast-${Date.now()}`
337
- setToasts(prev => [...prev, { id, message, type }])
338
- setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 5000)
339
- }, [])
533
+ ### Registro Basico
340
534
 
341
- useEffect(() => {
342
- // Escuchar notificaciones de CUALQUIER MFE
343
- const unsubscribe = on('notification:new', (event) => {
344
- const { message, type } = event.data || {}
345
- if (message) addToast(message, type || 'info')
346
- })
347
- return () => unsubscribe?.()
348
- }, [on, addToast])
535
+ ```jsx
536
+ import { wuSolid } from 'wu-framework/adapters/solid';
537
+ import App from './App';
538
+
539
+ wuSolid.register('my-app', App);
540
+ ```
541
+
542
+ ### Stores Reactivos
543
+
544
+ ```jsx
545
+ import { createWuStore, createWuEvent } from 'wu-framework/adapters/solid';
546
+
547
+ function MyComponent() {
548
+ const [user, setUser] = createWuStore('user');
549
+ const lastEvent = createWuEvent('notification:*');
349
550
 
350
551
  return (
351
- <div className="toast-container">
352
- {toasts.map(toast => (
353
- <div key={toast.id} className={`toast toast--${toast.type}`}>
354
- {toast.message}
355
- </div>
356
- ))}
552
+ <div>
553
+ <p>Hello, {user()?.name}</p>
554
+ <Show when={lastEvent()}>
555
+ <p>Last notification: {lastEvent()?.data}</p>
556
+ </Show>
557
+ <button onClick={() => setUser('name', 'John')}>
558
+ Set Name
559
+ </button>
357
560
  </div>
358
- )
561
+ );
359
562
  }
360
563
  ```
361
564
 
362
565
  ---
363
566
 
364
- ## πŸ“‘ Cross-MFE Communication
567
+ ## Lit Adapter (Web Components)
365
568
 
366
- ### Event Bus
569
+ ### Registro con LitElement
367
570
 
368
- ```ts
369
- import { emit, on, once, off } from 'wu-framework'
571
+ ```js
572
+ import { LitElement, html, css } from 'lit';
573
+ import { wuLit } from 'wu-framework/adapters/lit';
370
574
 
371
- // React MFE emite
372
- emit('notification:new', { message: 'Hello!', type: 'success' })
575
+ class MyApp extends LitElement {
576
+ static styles = css`
577
+ :host { display: block; padding: 16px; }
578
+ `;
373
579
 
374
- // Vue MFE escucha
375
- const unsubscribe = on('notification:new', (event) => {
376
- console.log(event.data.message) // 'Hello!'
377
- })
580
+ render() {
581
+ return html`<h1>Hello from Lit!</h1>`;
582
+ }
583
+ }
378
584
 
379
- // Wildcards - escuchar todos los eventos de notificaciΓ³n
380
- on('notification:*', (event) => {
381
- console.log('Event:', event.name, event.data)
382
- })
585
+ wuLit.register('my-app', MyApp);
586
+ ```
587
+
588
+ ### Con WuMixin
383
589
 
384
- // Una sola vez
385
- once('app:ready', () => console.log('Ready!'))
590
+ ```js
591
+ import { LitElement, html } from 'lit';
592
+ import { WuMixin } from 'wu-framework/adapters/lit';
386
593
 
387
- // Limpiar
388
- unsubscribe()
594
+ class MyApp extends WuMixin(LitElement) {
595
+ connectedCallback() {
596
+ super.connectedCallback();
597
+ this.wuOn('user:login', (data) => {
598
+ console.log('User logged in:', data);
599
+ });
600
+ }
601
+
602
+ handleClick() {
603
+ this.wuEmit('button:clicked', { id: 'my-button' });
604
+ }
605
+
606
+ render() {
607
+ return html`
608
+ <button @click=${this.handleClick}>Click me</button>
609
+ `;
610
+ }
611
+ }
612
+
613
+ wuLit.register('my-app', MyApp);
389
614
  ```
390
615
 
391
- ### Store Reactivo
616
+ ### Web Component Vanilla (sin Lit)
392
617
 
393
- ```ts
394
- import { getState, setState, onStateChange, batchState } from 'wu-framework'
618
+ ```js
619
+ import { wuLit } from 'wu-framework/adapters/lit';
395
620
 
396
- // Vue MFE escribe
397
- setState('notifications.count', 5)
398
- setState('user.theme', 'dark')
621
+ class MyComponent extends HTMLElement {
622
+ connectedCallback() {
623
+ this.attachShadow({ mode: 'open' });
624
+ this.shadowRoot.innerHTML = '<h1>Hello Web Component!</h1>';
625
+ }
626
+ }
399
627
 
400
- // React MFE lee
401
- const count = getState('notifications.count') // 5
628
+ wuLit.registerWebComponent('my-component', MyComponent);
629
+ ```
402
630
 
403
- // Angular MFE se suscribe
404
- const unsub = onStateChange('notifications.*', (value, path) => {
405
- console.log(`${path} changed:`, value)
406
- })
631
+ ---
632
+
633
+ ## Vanilla JS Adapter
634
+
635
+ ### Registro con Objeto
636
+
637
+ ```js
638
+ import { wuVanilla } from 'wu-framework/adapters/vanilla';
639
+
640
+ wuVanilla.register('my-app', {
641
+ state: { count: 0 },
642
+
643
+ render: (container, state) => {
644
+ container.innerHTML = `
645
+ <div>
646
+ <h1>Count: ${state.count}</h1>
647
+ <button id="increment">+</button>
648
+ </div>
649
+ `;
650
+ container.querySelector('#increment').onclick = () => {
651
+ state.count++;
652
+ };
653
+ },
654
+
655
+ destroy: (container) => {
656
+ container.innerHTML = '';
657
+ }
658
+ });
659
+ ```
660
+
661
+ ### Registro con Clase
662
+
663
+ ```js
664
+ import { wuVanilla } from 'wu-framework/adapters/vanilla';
665
+
666
+ class TodoApp {
667
+ constructor(container) {
668
+ this.container = container;
669
+ this.todos = [];
670
+ }
671
+
672
+ render() {
673
+ this.container.innerHTML = `
674
+ <ul>
675
+ ${this.todos.map(t => `<li>${t}</li>`).join('')}
676
+ </ul>
677
+ <input type="text" id="input" />
678
+ <button id="add">Add</button>
679
+ `;
680
+
681
+ this.container.querySelector('#add').onclick = () => {
682
+ const input = this.container.querySelector('#input');
683
+ this.todos.push(input.value);
684
+ this.render();
685
+ };
686
+ }
687
+
688
+ destroy() {
689
+ this.container.innerHTML = '';
690
+ }
691
+ }
692
+
693
+ wuVanilla.registerClass('todo-app', TodoApp);
694
+ ```
695
+
696
+ ### Registro con Template
697
+
698
+ ```js
699
+ import { wuVanilla } from 'wu-framework/adapters/vanilla';
700
+
701
+ wuVanilla.registerTemplate('header', `
702
+ <header>
703
+ <h1>My Header</h1>
704
+ <nav>
705
+ <a href="/">Home</a>
706
+ <a href="/about">About</a>
707
+ </nav>
708
+ </header>
709
+ `);
710
+
711
+ // Template dinamico
712
+ wuVanilla.registerTemplate('greeting',
713
+ (data) => `<h1>Hello, ${data.name}!</h1>`,
714
+ { data: { name: 'World' } }
715
+ );
716
+ ```
717
+
718
+ ### Componente Reactivo
719
+
720
+ ```js
721
+ import { wuVanilla } from 'wu-framework/adapters/vanilla';
722
+
723
+ const Counter = wuVanilla.createComponent({
724
+ state: { count: 0 },
725
+
726
+ template: (state) => `
727
+ <div>
728
+ <h1>Count: ${state.count}</h1>
729
+ <button data-action="increment">+</button>
730
+ <button data-action="decrement">-</button>
731
+ </div>
732
+ `,
733
+
734
+ actions: {
735
+ increment: (state) => ({ count: state.count + 1 }),
736
+ decrement: (state) => ({ count: state.count - 1 })
737
+ }
738
+ });
739
+
740
+ wuVanilla.register('counter', Counter);
741
+ ```
742
+
743
+ ---
407
744
 
408
- // Batch updates
745
+ ## Event Bus
746
+
747
+ Sistema de eventos para comunicacion entre microfrontends con soporte para wildcards y replay.
748
+
749
+ ```js
750
+ import { emit, on, once, off, replayEvents } from 'wu-framework';
751
+
752
+ // Emitir evento
753
+ emit('user:login', { userId: 123, name: 'John' });
754
+
755
+ // Suscribirse a evento
756
+ const unsubscribe = on('user:login', (event) => {
757
+ console.log('User logged in:', event.data);
758
+ });
759
+
760
+ // Suscribirse con wildcards
761
+ on('user:*', (event) => {
762
+ console.log('User event:', event.name, event.data);
763
+ });
764
+
765
+ // Suscribirse una sola vez
766
+ once('app:ready', (event) => {
767
+ console.log('App is ready!');
768
+ });
769
+
770
+ // Desuscribirse
771
+ off('user:login', callback);
772
+ unsubscribe();
773
+
774
+ // Replay eventos del historial
775
+ replayEvents('user:*', (event) => {
776
+ console.log('Past event:', event);
777
+ });
778
+ ```
779
+
780
+ ---
781
+
782
+ ## Store (State Management)
783
+
784
+ Store de alto rendimiento con pattern matching.
785
+
786
+ ```js
787
+ import {
788
+ getState,
789
+ setState,
790
+ onStateChange,
791
+ batchState,
792
+ clearState,
793
+ getStoreMetrics
794
+ } from 'wu-framework';
795
+
796
+ // Establecer estado (dot notation)
797
+ setState('user.name', 'John');
798
+ setState('user.preferences.theme', 'dark');
799
+
800
+ // Obtener estado
801
+ const name = getState('user.name'); // 'John'
802
+ const user = getState('user'); // { name: 'John', preferences: { theme: 'dark' } }
803
+
804
+ // Suscribirse a cambios
805
+ const unsubscribe = onStateChange('user.name', (value, path) => {
806
+ console.log(`${path} changed to:`, value);
807
+ });
808
+
809
+ // Suscribirse con wildcards
810
+ onStateChange('user.*', (value, path) => {
811
+ console.log(`User property changed: ${path} =`, value);
812
+ });
813
+
814
+ // Batch updates (mas eficiente)
409
815
  batchState({
410
- 'user.name': 'John',
411
- 'notifications.count': 0
412
- })
816
+ 'user.name': 'Jane',
817
+ 'user.email': 'jane@example.com',
818
+ 'settings.notifications': true
819
+ });
820
+
821
+ // Metricas de performance
822
+ const metrics = getStoreMetrics();
413
823
  ```
414
824
 
415
- ### Hooks por Framework
825
+ ---
416
826
 
417
- **React:**
418
- ```tsx
419
- import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/react'
827
+ ## Sistema de Plugins
420
828
 
421
- const useWuEvents = createUseWuEvents(React)
422
- const useWuStore = createUseWuStore(React)
829
+ ```js
830
+ import { usePlugin, createPlugin, uninstallPlugin } from 'wu-framework';
423
831
 
424
- function MyComponent() {
425
- const { emit, on } = useWuEvents()
426
- const { state, setState } = useWuStore('notifications')
832
+ const analyticsPlugin = createPlugin({
833
+ name: 'analytics',
834
+ permissions: ['events', 'store'],
427
835
 
428
- useEffect(() => {
429
- return on('user:login', (e) => console.log(e.data))
430
- }, [])
836
+ install: (api, options) => {
837
+ api.on('app:mounted', (event) => {
838
+ trackEvent('mount', event.data.appName);
839
+ });
840
+ },
841
+
842
+ beforeMount: async (context) => {
843
+ console.log('Before mount:', context.appName);
844
+ },
845
+
846
+ afterMount: async (context) => {
847
+ console.log('Mounted in', context.mountTime, 'ms');
848
+ }
849
+ });
850
+
851
+ usePlugin(analyticsPlugin, { trackingId: 'UA-123456' });
852
+ ```
853
+
854
+ ---
855
+
856
+ ## Lifecycle Hooks
857
+
858
+ ```js
859
+ import { useHook, createGuardHook, createTimedHook } from 'wu-framework';
860
+
861
+ // Hook basico
862
+ useHook('beforeMount', async (context, next) => {
863
+ console.log('Before mounting:', context.appName);
864
+ await next();
865
+ }, { name: 'my-hook', priority: 10 });
866
+
867
+ // Guard hook (puede cancelar)
868
+ const authGuard = createGuardHook(async (ctx) => {
869
+ return await isUserAuthenticated();
870
+ });
871
+ useHook('beforeMount', authGuard);
872
+
873
+ // Hook con timeout
874
+ const timedHook = createTimedHook(async (ctx) => {
875
+ await slowOperation();
876
+ }, 5000);
877
+ ```
878
+
879
+ ### Fases Disponibles
880
+
881
+ | Fase | Descripcion |
882
+ |------|-------------|
883
+ | `beforeInit` | Antes de inicializar framework |
884
+ | `afterInit` | Despues de inicializar |
885
+ | `beforeLoad` | Antes de cargar una app |
886
+ | `afterLoad` | Despues de cargar |
887
+ | `beforeMount` | Antes de montar |
888
+ | `afterMount` | Despues de montar |
889
+ | `beforeUnmount` | Antes de desmontar |
890
+ | `afterUnmount` | Despues de desmontar |
891
+
892
+ ---
893
+
894
+ ## Loading Strategies
895
+
896
+ ```js
897
+ await wu.init({
898
+ apps: [
899
+ { name: 'header', url: '/mfe/header', strategy: 'lazy' },
900
+ { name: 'sidebar', url: '/mfe/sidebar', strategy: 'eager' },
901
+ { name: 'footer', url: '/mfe/footer', strategy: 'preload' },
902
+ { name: 'analytics', url: '/mfe/analytics', strategy: 'idle' }
903
+ ]
904
+ });
905
+ ```
906
+
907
+ | Estrategia | Descripcion | Uso recomendado |
908
+ |------------|-------------|-----------------|
909
+ | `lazy` | Carga cuando se monta (default) | Contenido below-the-fold |
910
+ | `eager` | Precarga inmediata | Componentes criticos |
911
+ | `preload` | Usa `<link rel="prefetch">` | Navegacion anticipada |
912
+ | `idle` | Usa `requestIdleCallback` | Analytics, features secundarias |
913
+
914
+ ---
431
915
 
432
- return <span>Count: {state?.count || 0}</span>
916
+ ## Performance Monitoring
917
+
918
+ ```js
919
+ import {
920
+ startMeasure,
921
+ endMeasure,
922
+ getPerformanceMetrics,
923
+ generatePerformanceReport
924
+ } from 'wu-framework';
925
+
926
+ // Medicion personalizada
927
+ startMeasure('data-fetch', 'my-app');
928
+ await fetchData();
929
+ const duration = endMeasure('data-fetch', 'my-app');
930
+
931
+ // Reporte completo
932
+ const report = generatePerformanceReport();
933
+ ```
934
+
935
+ ---
936
+
937
+ ## Error Handling
938
+
939
+ ```js
940
+ import { registerErrorHandler, configureErrorBoundary } from 'wu-framework';
941
+
942
+ registerErrorHandler({
943
+ name: 'api-error',
944
+ canHandle: (error) => error.message.includes('API'),
945
+ handle: async (error, context) => {
946
+ if (context.retryCount < 3) {
947
+ return { recovered: true, action: 'retry' };
948
+ }
949
+ return { recovered: false, action: 'fallback' };
950
+ }
951
+ });
952
+
953
+ configureErrorBoundary({
954
+ maxRetries: 3,
955
+ retryDelay: 1000,
956
+ showErrorUI: true
957
+ });
958
+ ```
959
+
960
+ ---
961
+
962
+ ## API Simplificada (wu.app)
963
+
964
+ ```js
965
+ import { wu } from 'wu-framework';
966
+
967
+ const header = wu.app('header', {
968
+ url: 'http://localhost:3001',
969
+ container: '#header-container'
970
+ });
971
+
972
+ await header.mount();
973
+ console.log(header.isMounted); // true
974
+
975
+ await header.unmount();
976
+ await header.remount();
977
+ await header.reload(); // Limpia cache
978
+
979
+ const health = await header.verify();
980
+ await header.destroy();
981
+ ```
982
+
983
+ ---
984
+
985
+ ## Sistema de Build
986
+
987
+ Wu Framework incluye un sistema de build completo para proteger el codigo.
988
+
989
+ ### Comandos Disponibles
990
+
991
+ ```bash
992
+ # Instalar dependencias
993
+ npm install
994
+
995
+ # Build completo (todos los formatos)
996
+ npm run build
997
+
998
+ # Builds individuales
999
+ npm run build:dev # Desarrollo (sin minificar)
1000
+ npm run build:prod # Produccion (minificado)
1001
+ npm run build:obf # Ofuscado
1002
+ npm run build:umd # UMD para browsers
1003
+ npm run build:cjs # CommonJS para Node
1004
+
1005
+ # Build protegido (pipeline completo)
1006
+ npm run build:protected # Bundle -> Minify -> Obfuscate -> Base64
1007
+ ```
1008
+
1009
+ ### Pipeline de Proteccion
1010
+
1011
+ ```
1012
+ Source Code
1013
+ |
1014
+ v
1015
+ [1] Bundle (Rollup) -> Empaqueta todos los modulos
1016
+ |
1017
+ v
1018
+ [2] Minify (Terser) -> Reduce ~60% del tamanio
1019
+ |
1020
+ v
1021
+ [3] Obfuscate -> Codigo ilegible
1022
+ |
1023
+ v
1024
+ [4] Base64 Encode -> Capa adicional de proteccion
1025
+ |
1026
+ v
1027
+ Output: wu-framework.protected.js (~250KB)
1028
+ ```
1029
+
1030
+ ### Archivos Generados
1031
+
1032
+ | Archivo | Formato | Uso |
1033
+ |---------|---------|-----|
1034
+ | `wu-framework.dev.js` | ES Module | Desarrollo |
1035
+ | `wu-framework.min.js` | ES Module | Produccion |
1036
+ | `wu-framework.obf.js` | ES Module | Produccion protegida |
1037
+ | `wu-framework.protected.js` | ES Module | Maxima proteccion |
1038
+ | `wu-framework.umd.js` | UMD | Browsers via CDN |
1039
+ | `wu-framework.cjs.js` | CommonJS | Node.js |
1040
+
1041
+ ---
1042
+
1043
+ ## Sandbox System
1044
+
1045
+ Wu Framework usa dos estrategias de aislamiento JS:
1046
+
1047
+ ### Proxy Sandbox (Default)
1048
+
1049
+ - Usa ES6 Proxy para interceptar acceso a globales
1050
+ - Aislamiento completo sin side effects
1051
+ - Requiere soporte de Proxy (navegadores modernos)
1052
+
1053
+ ### Snapshot Sandbox (Fallback)
1054
+
1055
+ - Toma snapshots del estado global
1056
+ - Restaura al desmontar
1057
+ - Compatible con navegadores legacy
1058
+
1059
+ ```js
1060
+ // El framework detecta automaticamente la mejor estrategia
1061
+ const stats = wu.sandbox.getStats();
1062
+ console.log(stats.strategy); // 'proxy' o 'snapshot'
1063
+ ```
1064
+
1065
+ ---
1066
+
1067
+ ## Deployment
1068
+
1069
+ ### Estructura de Produccion
1070
+
1071
+ ```
1072
+ https://cdn.mycompany.com/
1073
+ β”œβ”€β”€ mfe/
1074
+ β”‚ β”œβ”€β”€ header/
1075
+ β”‚ β”‚ β”œβ”€β”€ wu.json
1076
+ β”‚ β”‚ β”œβ”€β”€ index.js
1077
+ β”‚ β”‚ └── assets/
1078
+ β”‚ β”œβ”€β”€ sidebar/
1079
+ β”‚ β”‚ β”œβ”€β”€ wu.json
1080
+ β”‚ β”‚ β”œβ”€β”€ index.js
1081
+ β”‚ β”‚ └── assets/
1082
+ β”‚ └── content/
1083
+ β”‚ β”œβ”€β”€ wu.json
1084
+ β”‚ β”œβ”€β”€ index.js
1085
+ β”‚ └── assets/
1086
+ ```
1087
+
1088
+ ### Configuracion por Entorno
1089
+
1090
+ ```js
1091
+ const config = {
1092
+ development: {
1093
+ header: 'http://localhost:3001',
1094
+ sidebar: 'http://localhost:3002',
1095
+ content: 'http://localhost:3003'
1096
+ },
1097
+ staging: {
1098
+ header: 'https://staging-cdn.mycompany.com/mfe/header',
1099
+ sidebar: 'https://staging-cdn.mycompany.com/mfe/sidebar',
1100
+ content: 'https://staging-cdn.mycompany.com/mfe/content'
1101
+ },
1102
+ production: {
1103
+ header: 'https://cdn.mycompany.com/mfe/header',
1104
+ sidebar: 'https://cdn.mycompany.com/mfe/sidebar',
1105
+ content: 'https://cdn.mycompany.com/mfe/content'
1106
+ }
1107
+ };
1108
+
1109
+ const env = process.env.NODE_ENV || 'development';
1110
+ const urls = config[env];
1111
+
1112
+ await wu.init({
1113
+ apps: [
1114
+ { name: 'header', url: urls.header },
1115
+ { name: 'sidebar', url: urls.sidebar },
1116
+ { name: 'content', url: urls.content }
1117
+ ]
1118
+ });
1119
+ ```
1120
+
1121
+ ### CORS Configuration
1122
+
1123
+ ```nginx
1124
+ location /mfe/ {
1125
+ add_header Access-Control-Allow-Origin *;
1126
+ add_header Access-Control-Allow-Methods "GET, OPTIONS";
1127
+ add_header Access-Control-Allow-Headers "Content-Type";
433
1128
  }
434
1129
  ```
435
1130
 
436
- **Vue:**
437
- ```vue
438
- <script setup>
439
- import { useWuEvents, useWuStore } from 'wu-framework/adapters/vue'
1131
+ ### Versionado
440
1132
 
441
- const { emit, on } = useWuEvents()
442
- const { state, setState } = useWuStore('cart')
1133
+ ```json
1134
+ {
1135
+ "name": "header",
1136
+ "version": "1.2.0",
1137
+ "entry": "index.js"
1138
+ }
1139
+ ```
443
1140
 
444
- onMounted(() => {
445
- on('cart:updated', (data) => console.log(data))
446
- })
447
- </script>
1141
+ ```js
1142
+ await wu.init({
1143
+ apps: [
1144
+ { name: 'header', url: 'https://cdn.mycompany.com/mfe/header/v1.2.0' },
1145
+ { name: 'sidebar', url: 'https://cdn.mycompany.com/mfe/sidebar/v2.0.0' }
1146
+ ]
1147
+ });
448
1148
  ```
449
1149
 
450
1150
  ---
451
1151
 
452
- ## πŸ—οΈ Arquitectura
1152
+ ## Arquitectura
453
1153
 
454
1154
  ```
455
1155
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
456
- β”‚ SHELL (React) β”‚
457
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
458
- β”‚ β”‚ ToastContainer (escucha notification:new) β”‚ β”‚
459
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
1156
+ β”‚ HOST APPLICATION β”‚
460
1157
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
461
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
462
- β”‚ β”‚ #shadow-root β”‚ β”‚ #shadow-root β”‚ β”‚
463
- β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
464
- β”‚ β”‚ β”‚ Header β”‚ β”‚ ──────▢ β”‚ β”‚ Content β”‚ β”‚ β”‚
465
- β”‚ β”‚ β”‚ (Vue) β”‚ β”‚ events β”‚ β”‚ (React) β”‚ β”‚ β”‚
466
- β”‚ β”‚ β”‚ β”‚ β”‚ ◀────── β”‚ β”‚ β”‚ β”‚ β”‚
467
- β”‚ β”‚ β”‚ πŸ”” badge β”‚ β”‚ store β”‚ β”‚ [Send Notif] β”‚ β”‚ β”‚
468
- β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
469
- β”‚ β”‚ fully-isolated β”‚ β”‚ isolated β”‚ β”‚
470
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
1158
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
1159
+ β”‚ β”‚ #shadow-root β”‚ β”‚ #shadow-root β”‚ β”‚ #shadow-rootβ”‚ β”‚
1160
+ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
1161
+ β”‚ β”‚ β”‚ Header β”‚ β”‚ β”‚ β”‚ Sidebar β”‚ β”‚ β”‚ β”‚ Content β”‚ β”‚ β”‚
1162
+ β”‚ β”‚ β”‚ (React) β”‚ β”‚ β”‚ β”‚ (Vue) β”‚ β”‚ β”‚ β”‚(Angular)β”‚ β”‚ β”‚
1163
+ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
1164
+ β”‚ β”‚ CSS Isolated β”‚ β”‚ CSS Isolated β”‚ β”‚ CSS Isolatedβ”‚ β”‚
1165
+ β”‚ β”‚ JS Sandboxed β”‚ β”‚ JS Sandboxed β”‚ β”‚ JS Sandboxedβ”‚ β”‚
1166
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
471
1167
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
472
- β”‚ WU FRAMEWORK CORE β”‚
473
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
474
- β”‚ β”‚ EventBus β”‚ β”‚ Store β”‚ β”‚StyleBridgeβ”‚ β”‚ Sandbox Pool β”‚ β”‚
475
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
1168
+ β”‚ WU FRAMEWORK CORE β”‚
1169
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
1170
+ β”‚ β”‚ EventBus β”‚ β”‚ Store β”‚ β”‚ Plugins β”‚ β”‚ Sandbox Pool β”‚ β”‚
1171
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
1172
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
1173
+ β”‚ β”‚ Loader β”‚ β”‚ Manifest β”‚ β”‚ Hooks β”‚ β”‚ Style Bridge β”‚ β”‚
1174
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
476
1175
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
477
1176
  ```
478
1177
 
479
- **Flujo de datos:**
480
- 1. React Dashboard (content) llama `emit('notification:new', {...})`
481
- 2. Wu EventBus propaga a todos los suscriptores
482
- 3. Vue NavBar (header) incrementa badge
483
- 4. React ToastContainer (shell) muestra toast flotante
484
- 5. Store compartido actualiza `notifications.count`
485
-
486
1178
  ---
487
1179
 
488
- ## 🎨 Adapters
1180
+ ## API Reference
489
1181
 
490
- | Framework | Adapter | Registro |
491
- |-----------|---------|----------|
492
- | βš›οΈ React | `wuReact` | `wuReact.register('app', App)` |
493
- | πŸ’š Vue 3 | `wuVue` | `wuVue.register('app', App)` |
494
- | πŸ…°οΈ Angular | `wuAngular` | `wuAngular.register('app', AppModule)` |
495
- | 🧑 Svelte | `wuSvelte` | `wuSvelte.register('app', App)` |
496
- | ⚑ Preact | `wuPreact` | `wuPreact.register('app', App)` |
497
- | πŸ’Ž Solid.js | `wuSolid` | `wuSolid.register('app', App)` |
498
- | πŸ”₯ Lit | `wuLit` | `wuLit.register('app', MyElement)` |
499
- | πŸ“¦ Vanilla | `wuVanilla` | `wuVanilla.register('app', config)` |
1182
+ ### Core
500
1183
 
501
- ---
1184
+ ```js
1185
+ import { wu, init, mount, unmount, destroy, getStats } from 'wu-framework';
1186
+ ```
502
1187
 
503
- ## βš™οΈ Core Systems
1188
+ ### Event Bus
504
1189
 
505
- | Sistema | DescripciΓ³n |
506
- |---------|-------------|
507
- | **WuStyleBridge** | Detecta estilos por puerto/carpeta, inyecta en Shadow DOM, genera reset de CSS vars |
508
- | **WuSandbox** | Proxy Sandbox para JS isolation, cleanup automΓ‘tico |
509
- | **WuEventBus** | Wildcards, replay, mΓ©tricas |
510
- | **WuStore** | Dot notation, wildcard subscriptions, batch |
511
- | **WuCache** | Cache de manifests y mΓ³dulos |
512
- | **WuPerformance** | Tiempos de mount/unmount, reportes |
513
- | **WuErrorBoundary** | Auto-retry, fallback UI |
514
- | **WuPluginSystem** | Lifecycle hooks, middleware |
1190
+ ```js
1191
+ import { emit, on, once, off, replayEvents, getEventBusStats } from 'wu-framework';
1192
+ ```
515
1193
 
516
- ---
1194
+ ### Store
517
1195
 
518
- ## πŸ“‹ API Reference
1196
+ ```js
1197
+ import { getState, setState, onStateChange, batchState, clearState } from 'wu-framework';
1198
+ ```
519
1199
 
520
- ```ts
521
- // Core
522
- import { wu, init, mount, unmount, destroy } from 'wu-framework'
1200
+ ### Plugins & Hooks
1201
+
1202
+ ```js
1203
+ import { usePlugin, createPlugin, useHook, removeHook } from 'wu-framework';
1204
+ ```
1205
+
1206
+ ### Performance & Errors
1207
+
1208
+ ```js
1209
+ import { startMeasure, endMeasure, generatePerformanceReport } from 'wu-framework';
1210
+ import { registerErrorHandler, configureErrorBoundary } from 'wu-framework';
1211
+ ```
1212
+
1213
+ ### Style Management
1214
+
1215
+ ```js
1216
+ import { configureStyleSharing, reinjectStyles, getStyleStats } from 'wu-framework';
1217
+ ```
1218
+
1219
+ ### Adapters
1220
+
1221
+ ```js
1222
+ import { wuReact } from 'wu-framework/adapters/react';
1223
+ import { wuVue } from 'wu-framework/adapters/vue';
1224
+ import { wuAngular } from 'wu-framework/adapters/angular';
1225
+ import { wuSvelte } from 'wu-framework/adapters/svelte';
1226
+ import { wuPreact } from 'wu-framework/adapters/preact';
1227
+ import { wuSolid } from 'wu-framework/adapters/solid';
1228
+ import { wuLit } from 'wu-framework/adapters/lit';
1229
+ import { wuVanilla } from 'wu-framework/adapters/vanilla';
1230
+ ```
523
1231
 
524
- // Events
525
- import { emit, on, once, off, replayEvents } from 'wu-framework'
1232
+ ### Utilities
526
1233
 
527
- // Store
528
- import { getState, setState, onStateChange, batchState } from 'wu-framework'
1234
+ ```js
1235
+ import { presets, dev, events } from 'wu-framework';
529
1236
 
530
- // Performance
531
- import { startMeasure, endMeasure, generatePerformanceReport } from 'wu-framework'
1237
+ // Presets
1238
+ await wu.init(presets.development([{ name: 'app', port: 3001 }]));
1239
+ await wu.init(presets.production([{ name: 'app', url: 'https://...' }]));
532
1240
 
533
- // Plugins
534
- import { usePlugin, createPlugin, useHook } from 'wu-framework'
1241
+ // Dev tools
1242
+ dev.enableDebug();
1243
+ dev.inspect();
1244
+ await dev.reload('app');
535
1245
 
536
- // Adapters
537
- import { wuReact } from 'wu-framework/adapters/react'
538
- import { wuVue } from 'wu-framework/adapters/vue'
1246
+ // Silenciar logs
1247
+ wu.silence();
1248
+ wu.verbose();
539
1249
  ```
540
1250
 
541
1251
  ---
542
1252
 
543
- ## πŸ“„ License
1253
+ ## Contributing
1254
+
1255
+ Las contribuciones son bienvenidas!
1256
+
1257
+ 1. **Fork** el repositorio
1258
+ 2. **Crear** branch (`git checkout -b feature/amazing-feature`)
1259
+ 3. **Commit** tus cambios (`git commit -m 'Add amazing feature'`)
1260
+ 4. **Push** al branch (`git push origin feature/amazing-feature`)
1261
+ 5. **Abrir** un Pull Request
1262
+
1263
+ ---
1264
+
1265
+ ## License
544
1266
 
545
1267
  MIT License - Copyright (c) 2025 Wu Framework Team
546
1268
 
547
1269
  ---
548
1270
 
549
- <p align="center">
550
- <b>πŸš€ Wu Framework - Universal Microfrontends Made Simple</b>
551
- <br><br>
552
- <i>Shadow DOM β€’ 4 CSS Isolation Modes β€’ Cross-MFE Events & Store β€’ Zero Config</i>
553
- </p>
1271
+ **Wu Framework - Universal Microfrontends Made Simple**
1272
+
1273
+ *Zero dependencies - 8 Frameworks - Shadow DOM - Proxy Sandbox - Self-Healing - Build Protection*