wu-framework 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,1032 +2,449 @@
2
2
 
3
3
  **Universal Microfrontends Made Simple**
4
4
 
5
- Wu Framework es la librería de microfrontends más simple y poderosa del mercado. **Framework agnostic, zero config, Shadow DOM nativo**.
6
-
7
- ## ✨ ¿Por qué Wu Framework?
8
-
9
- | Característica | Module Federation | qiankun | **Wu Framework** |
10
- |---|---|---|---|
11
- | **Setup** | Webpack config complejo | Configuración manual | **Zero config** |
12
- | **Framework Support** | React-first | Multi framework | **8 frameworks nativos** |
13
- | **Bundler Required** | Solo Webpack 5 | Agnóstico pero complejo | **Ninguno** |
14
- | **CSS Isolation** | Básico | CSS hacks | **Shadow DOM nativo** |
15
- | **JS Isolation** | ❌ | Proxy básico | **Proxy Sandbox completo** |
16
- | **Runtime Config** | ❌ | Limitado | **✅ Completamente dinámico** |
17
- | **Self-Healing** | ❌ | ❌ | **✅ Auto-recovery** |
18
- | **API Complexity** | Alta | Media | **1 línea de código** |
19
-
20
- ## 🎯 Instalación
21
-
22
- ```bash
23
- npm install wu-framework
24
- ```
25
-
26
- **¡Y ya está!** Sin webpack config, sin plugins, sin configuración.
5
+ Wu Framework es una librería de microfrontends con **Shadow DOM nativo**, **aislamiento CSS avanzado**, y **comunicación cross-MFE** integrada.
27
6
 
28
7
  ---
29
8
 
30
- ## 🎨 Frameworks Soportados
9
+ ## ¿Por qué Wu Framework?
31
10
 
32
- Wu Framework incluye **adapters nativos** para los frameworks más populares:
33
-
34
- | Framework | Adapter | Registro |
35
- |-----------|---------|----------|
36
- | ⚛️ React | `wuReact` | `wuReact.register('app', App)` |
37
- | 💚 Vue | `wuVue` | `wuVue.register('app', App)` |
38
- | 🅰️ Angular | `wuAngular` | `wuAngular.register('app', AppModule)` |
39
- | 🧡 Svelte | `wuSvelte` | `wuSvelte.register('app', App)` |
40
- | Preact | `wuPreact` | `wuPreact.register('app', App)` |
41
- | 💎 Solid.js | `wuSolid` | `wuSolid.register('app', App)` |
42
- | 🔥 Lit | `wuLit` | `wuLit.register('app', MyElement)` |
43
- | 📦 Vanilla JS | `wuVanilla` | `wuVanilla.register('app', config)` |
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** |
44
21
 
45
22
  ---
46
23
 
47
- ## 🔥 Quick Start
48
-
49
- ### 1. Micro App: Crear `wu.json`
24
+ ## 🛡️ CSS Isolation Modes (Feature Único)
50
25
 
51
- Cada microfrontend necesita un archivo `wu.json` en su raíz:
26
+ Wu Framework ofrece **4 modos de aislamiento CSS**. El modo `fully-isolated` es **único** - bloquea incluso las CSS variables del padre:
52
27
 
53
28
  ```json
29
+ // header/wu.json - Aislamiento total (bloquea CSS vars del padre)
54
30
  {
55
31
  "name": "header",
56
- "entry": "index.js",
32
+ "entry": "src/main.ts",
33
+ "styleMode": "fully-isolated",
57
34
  "wu": {
58
- "exports": {
59
- "NavBar": "components/NavBar.js",
60
- "UserMenu": "components/UserMenu.js"
61
- },
62
- "imports": [],
63
- "routes": ["/", "/home"],
64
35
  "permissions": ["events", "store"]
65
36
  }
66
37
  }
67
38
  ```
68
39
 
69
- | Campo | Descripción |
70
- |-------|-------------|
71
- | `name` | Nombre único del microfrontend |
72
- | `entry` | Archivo JS principal (default: `index.js`) |
73
- | `wu.exports` | Componentes que expone a otros microfrontends |
74
- | `wu.imports` | Componentes que importa de otros microfrontends |
75
- | `wu.routes` | Rutas que maneja este microfrontend |
76
- | `wu.permissions` | Permisos requeridos (`events`, `store`, `dom`) |
77
-
78
- ### 2. Micro App: Registrar con Adapter (1 línea)
79
-
80
- **React:**
81
- ```tsx
82
- import { wuReact } from 'wu-framework/adapters/react';
83
- import App from './App';
84
-
85
- wuReact.register('header', App);
86
- ```
87
-
88
- **Vue:**
89
- ```ts
90
- import { wuVue } from 'wu-framework/adapters/vue';
91
- import App from './App.vue';
92
-
93
- wuVue.register('sidebar', App);
94
- ```
95
-
96
- **Angular:**
97
- ```ts
98
- import { wuAngular } from 'wu-framework/adapters/angular';
99
- import { AppModule } from './app/app.module';
100
-
101
- wuAngular.register('content', AppModule);
102
- ```
103
-
104
- **¡Eso es todo!** El adapter se encarga de todo: detección de contexto, modo standalone, cleanup automático.
105
-
106
- ### 3. Shell (Host Application)
107
-
108
- **Desarrollo:**
109
- ```js
110
- import { wu } from 'wu-framework';
111
-
112
- await wu.init({
113
- apps: [
114
- { name: 'header', url: 'http://localhost:3001' },
115
- { name: 'sidebar', url: 'http://localhost:3002' },
116
- { name: 'content', url: 'http://localhost:3003' }
117
- ]
118
- });
119
-
120
- await wu.mount('header', '#header-container');
121
- await wu.mount('sidebar', '#sidebar-container');
122
- await wu.mount('content', '#content-container');
123
- ```
124
-
125
- **Producción:**
126
- ```js
127
- import { wu } from 'wu-framework';
128
-
129
- await wu.init({
130
- apps: [
131
- { name: 'header', url: 'https://cdn.mycompany.com/mfe/header' },
132
- { name: 'sidebar', url: 'https://cdn.mycompany.com/mfe/sidebar' },
133
- { name: 'content', url: 'https://cdn.mycompany.com/mfe/content' }
134
- ]
135
- });
136
-
137
- await wu.mount('header', '#header-container');
138
- await wu.mount('sidebar', '#sidebar-container');
139
- await wu.mount('content', '#content-container');
140
- ```
141
-
142
- **Con configuración dinámica:**
143
- ```js
144
- import { wu } from 'wu-framework';
145
-
146
- const isDev = process.env.NODE_ENV !== 'production';
147
-
148
- await wu.init({
149
- apps: [
150
- { name: 'header', url: isDev ? 'http://localhost:3001' : 'https://cdn.mycompany.com/mfe/header' },
151
- { name: 'sidebar', url: isDev ? 'http://localhost:3002' : 'https://cdn.mycompany.com/mfe/sidebar' },
152
- { name: 'content', url: isDev ? 'http://localhost:3003' : 'https://cdn.mycompany.com/mfe/content' }
153
- ]
154
- });
40
+ ```json
41
+ // container/wu.json - Aislamiento normal (hereda CSS vars)
42
+ {
43
+ "name": "content",
44
+ "folder": "container",
45
+ "entry": "src/main.tsx",
46
+ "styleMode": "isolated",
47
+ "wu": {
48
+ "permissions": ["events", "store"]
49
+ }
50
+ }
155
51
  ```
156
52
 
157
- ### Estructura de Archivos (Microfrontend)
158
-
159
- ```
160
- my-header-mfe/
161
- ├── wu.json # Manifest requerido
162
- ├── index.js # Entry point (registra con adapter)
163
- ├── App.jsx # ← Componente principal
164
- ├── components/
165
- │ ├── NavBar.js
166
- │ └── UserMenu.js
167
- └── package.json
168
- ```
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. |
169
59
 
170
60
  ---
171
61
 
172
- ## ⚛️ React Adapter
62
+ ## 🔥 Quick Start
173
63
 
174
- ### Registro Básico
64
+ ### 1. Shell (React + Vite)
175
65
 
176
66
  ```tsx
177
- import { wuReact } from 'wu-framework/adapters/react';
178
- import App from './App';
67
+ // shell/src/config/mfe.config.ts
68
+ const isDev = import.meta.env.DEV
179
69
 
180
- wuReact.register('my-app', App);
181
- ```
70
+ const devUrls = {
71
+ header: 'http://localhost:3001',
72
+ content: 'http://localhost:3003'
73
+ }
182
74
 
183
- ### Con Opciones
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
+ }
184
79
 
185
- ```tsx
186
- wuReact.register('my-app', App, {
187
- strictMode: true, // Envolver en React.StrictMode
188
- props: { theme: 'dark' }, // Props iniciales
189
- standalone: true, // Ejecutar independiente si Wu no está
190
- standaloneContainer: '#root',
191
- onMount: (container) => console.log('Mounted!'),
192
- onUnmount: (container) => console.log('Unmounted!')
193
- });
194
- ```
80
+ export const urls = isDev ? devUrls : prodUrls
195
81
 
196
- ### Hooks para React
82
+ export const enabledApps = [
83
+ { name: 'header', url: urls.header, enabled: true },
84
+ { name: 'content', url: urls.content, enabled: true }
85
+ ]
86
+ ```
197
87
 
198
88
  ```tsx
199
- import React from 'react';
200
- import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/react';
201
-
202
- const useWuEvents = createUseWuEvents(React);
203
- const useWuStore = createUseWuStore(React);
204
-
205
- function MyComponent() {
206
- const { emit, on } = useWuEvents();
207
- const { state, setState } = useWuStore('user');
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)
208
107
 
209
108
  useEffect(() => {
210
- const unsub = on('cart:updated', (data) => {
211
- console.log('Cart updated:', data);
212
- });
213
- return unsub;
214
- }, [on]);
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
+ }
215
122
 
216
- return (
217
- <button onClick={() => emit('user:logout')}>
218
- Logout {state?.name}
219
- </button>
220
- );
123
+ initWu()
124
+ }, [])
125
+
126
+ return { ...state, wu }
221
127
  }
222
128
  ```
223
129
 
224
- ### Cargar Microfrontends en React (Shell)
225
-
226
130
  ```tsx
227
- import React from 'react';
228
- import { createWuSlot } from 'wu-framework/adapters/react';
131
+ // shell/src/App.tsx
132
+ import { useWuFramework, useWuEvents } from './hooks/useWuFramework'
133
+ import WuSlot from './components/WuSlot'
134
+ import ToastContainer from './components/ToastContainer'
135
+
136
+ function App() {
137
+ const { initialized, loading, error } = useWuFramework()
138
+ const { emit } = useWuEvents()
229
139
 
230
- const WuSlot = createWuSlot(React);
140
+ useEffect(() => {
141
+ if (initialized) {
142
+ emit('shell:ready', { timestamp: Date.now() })
143
+ }
144
+ }, [initialized, emit])
231
145
 
232
- // URLs pueden ser localhost (dev) o CDN (prod)
233
- const HEADER_URL = process.env.REACT_APP_HEADER_URL || 'http://localhost:3001';
234
- const CONTENT_URL = process.env.REACT_APP_CONTENT_URL || 'http://localhost:3002';
146
+ if (loading) return <div>Loading Wu Framework...</div>
147
+ if (error) return <div>Error: {error.message}</div>
235
148
 
236
- function Shell() {
237
149
  return (
238
- <div>
239
- <WuSlot
240
- name="header"
241
- url={HEADER_URL}
242
- onLoad={() => console.log('Header loaded!')}
243
- onError={(err) => console.error(err)}
244
- />
245
- <WuSlot name="content" url={CONTENT_URL} />
246
- </div>
247
- );
150
+ <>
151
+ <ToastContainer />
152
+ <WuSlot name="header" url={urls.header} />
153
+ <WuSlot name="content" url={urls.content} />
154
+ </>
155
+ )
248
156
  }
249
157
  ```
250
158
 
251
- ---
252
-
253
- ## 💚 Vue Adapter
254
-
255
- ### Registro Básico
256
-
257
- ```ts
258
- import { wuVue } from 'wu-framework/adapters/vue';
259
- import App from './App.vue';
159
+ ### 2. MFE Header (Vue 3)
260
160
 
261
- wuVue.register('my-app', App);
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
+ }
262
174
  ```
263
175
 
264
- ### Con Plugins (Pinia, Router, etc.)
265
-
266
176
  ```ts
267
- import { wuVue } from 'wu-framework/adapters/vue';
268
- import { createPinia } from 'pinia';
269
- import router from './router';
270
- import App from './App.vue';
271
-
272
- wuVue.register('my-app', App, {
273
- setup: (app) => {
274
- app.use(createPinia());
275
- app.use(router);
276
- }
277
- });
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
+ })
278
189
  ```
279
190
 
280
- ### Composables para Vue
281
-
282
191
  ```vue
283
- <script setup>
284
- import { onMounted, onUnmounted } from 'vue';
285
- import { useWuEvents, useWuStore } from 'wu-framework/adapters/vue';
286
-
287
- const { emit, on, cleanup } = useWuEvents();
288
- const { state, setState } = useWuStore('cart');
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'
289
196
 
290
- onMounted(() => {
291
- on('user:login', (data) => console.log('Login:', data));
292
- });
197
+ const { emit, on } = useWuEvents()
198
+ const { state: notificationState, setState } = useWuStore('notifications')
293
199
 
294
- onUnmounted(() => cleanup());
295
- </script>
200
+ const notificationCount = ref(0)
201
+ let unsubscribe: (() => void) | null = null
296
202
 
297
- <template>
298
- <div>
299
- <p>Items: {{ state?.items?.length }}</p>
300
- <button @click="emit('cart:clear')">Clear Cart</button>
301
- </div>
302
- </template>
303
- ```
203
+ onMounted(() => {
204
+ // Inicializar store compartido
205
+ if (!notificationState.value) {
206
+ setState({ count: 0, items: [] })
207
+ }
304
208
 
305
- ### Cargar Microfrontends en Vue (Shell)
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
+ })
306
225
 
307
- ```vue
308
- <script setup>
309
- import { WuSlot } from 'wu-framework/adapters/vue';
226
+ onUnmounted(() => {
227
+ if (unsubscribe) unsubscribe()
228
+ })
310
229
 
311
- // URLs: localhost en dev, CDN en prod
312
- const headerUrl = import.meta.env.VITE_HEADER_URL || 'http://localhost:3001';
313
- const sidebarUrl = import.meta.env.VITE_SIDEBAR_URL || 'http://localhost:3002';
230
+ const handleNavClick = (item: { id: string, label: string }) => {
231
+ emit('header:nav:click', { id: item.id, label: item.label })
232
+ }
314
233
  </script>
315
234
 
316
235
  <template>
317
- <div>
318
- <WuSlot
319
- name="header"
320
- :url="headerUrl"
321
- @load="onLoad"
322
- @error="onError"
323
- />
324
- <WuSlot name="sidebar" :url="sidebarUrl" />
325
- </div>
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>
326
244
  </template>
327
245
  ```
328
246
 
329
- ### Plugin Global
330
-
331
- ```ts
332
- import { createApp } from 'vue';
333
- import { wuVuePlugin } from 'wu-framework/adapters/vue';
334
-
335
- const app = createApp(App);
336
- app.use(wuVuePlugin); // Registra <WuSlot> globalmente
337
- ```
338
-
339
- ---
340
-
341
- ## 🅰️ Angular Adapter
342
-
343
- ### Registro con NgModule
344
-
345
- ```ts
346
- import { wuAngular } from 'wu-framework/adapters/angular';
347
- import { AppModule } from './app/app.module';
348
-
349
- wuAngular.register('my-app', AppModule);
350
- ```
351
-
352
- ### Registro con Standalone Components (Angular 14+)
353
-
354
- ```ts
355
- import { wuAngular } from 'wu-framework/adapters/angular';
356
- import { AppComponent } from './app/app.component';
357
- import { appConfig } from './app/app.config';
358
-
359
- wuAngular.registerStandalone('my-app', AppComponent, {
360
- appConfig
361
- });
362
- ```
363
-
364
- ### Servicio para Componentes
365
-
366
- ```ts
367
- import { Component, OnInit, OnDestroy } from '@angular/core';
368
- import { createWuService } from 'wu-framework/adapters/angular';
247
+ ### 3. MFE Content (React)
369
248
 
370
- @Component({
371
- selector: 'app-root',
372
- template: `<button (click)="sendEvent()">Send Event</button>`
373
- })
374
- export class AppComponent implements OnInit, OnDestroy {
375
- private wuService = createWuService();
376
-
377
- ngOnInit() {
378
- this.wuService.on('user:login', (data) => {
379
- console.log('User logged in:', data);
380
- });
381
- }
382
-
383
- sendEvent() {
384
- this.wuService.emit('app:ready', { timestamp: Date.now() });
385
- }
386
-
387
- ngOnDestroy() {
388
- this.wuService.destroy();
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"]
389
261
  }
390
262
  }
391
263
  ```
392
264
 
393
- ---
394
-
395
- ## 🧡 Svelte Adapter
396
-
397
- ### Registro Básico
398
-
399
- ```js
400
- import { wuSvelte } from 'wu-framework/adapters/svelte';
401
- import App from './App.svelte';
402
-
403
- wuSvelte.register('my-app', App);
404
- ```
405
-
406
- ### Svelte 5 (con runes)
407
-
408
- ```js
409
- import { wuSvelte } from 'wu-framework/adapters/svelte';
410
- import App from './App.svelte';
411
-
412
- wuSvelte.registerSvelte5('my-app', App);
413
- ```
414
-
415
- ### Stores Reactivos
416
-
417
- ```svelte
418
- <script>
419
- import { createWuStore, useWuEvents } from 'wu-framework/adapters/svelte';
420
- import { onDestroy } from 'svelte';
421
-
422
- // Store reactivo (compatible con $store)
423
- const userStore = createWuStore('user');
424
-
425
- // Eventos
426
- const { emit, on, cleanup } = useWuEvents();
427
-
428
- on('cart:updated', (data) => {
429
- console.log('Cart updated:', data);
430
- });
431
-
432
- onDestroy(cleanup);
433
- </script>
434
-
435
- <p>Hello, {$userStore?.name}</p>
436
- <button on:click={() => emit('user:logout')}>Logout</button>
437
- ```
438
-
439
- ---
440
-
441
- ## ⚡ Preact Adapter
442
-
443
- ### Registro Básico
444
-
445
- ```jsx
446
- import { wuPreact } from 'wu-framework/adapters/preact';
447
- import App from './App';
448
-
449
- wuPreact.register('my-app', App);
450
- ```
451
-
452
- ### Compatible con React (preact/compat)
453
-
454
- ```jsx
455
- import { wuPreact } from 'wu-framework/adapters/preact';
456
- import App from './App'; // Componente estilo React
457
-
458
- wuPreact.registerCompat('my-app', App);
459
- ```
460
-
461
- ### Hooks
462
-
463
- ```jsx
464
- import { h } from 'preact';
465
- import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
466
- import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/preact';
467
-
468
- const useWuEvents = createUseWuEvents({ useCallback, useEffect, useRef });
469
- const useWuStore = createUseWuStore({ useState, useCallback, useEffect });
470
-
471
- function MyComponent() {
472
- const { emit, on } = useWuEvents();
473
- const { state } = useWuStore('user');
474
-
475
- return <div>Hello {state?.name}</div>;
476
- }
477
- ```
478
-
479
- ---
480
-
481
- ## 💎 Solid.js Adapter
482
-
483
- ### Registro Básico
484
-
485
- ```jsx
486
- import { wuSolid } from 'wu-framework/adapters/solid';
487
- import App from './App';
265
+ ```tsx
266
+ // container/src/main.tsx
267
+ import { wuReact } from 'wu-framework/adapters/react'
268
+ import App from './App'
488
269
 
489
- wuSolid.register('my-app', App);
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)
276
+ })
490
277
  ```
491
278
 
492
- ### Stores Reactivos
493
-
494
- ```jsx
495
- import { createWuStore, createWuEvent } from 'wu-framework/adapters/solid';
496
-
497
- function MyComponent() {
498
- // Store reactivo
499
- const [user, setUser] = createWuStore('user');
500
-
501
- // Eventos reactivos
502
- const lastEvent = createWuEvent('notification:*');
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)
292
+ }
503
293
 
504
294
  return (
505
- <div>
506
- <p>Hello, {user()?.name}</p>
507
- <Show when={lastEvent()}>
508
- <p>Last notification: {lastEvent()?.data}</p>
509
- </Show>
510
- <button onClick={() => setUser('name', 'John')}>
511
- Set Name
512
- </button>
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>
513
313
  </div>
514
- );
515
- }
516
- ```
517
-
518
- ---
519
-
520
- ## 🔥 Lit Adapter (Web Components)
521
-
522
- ### Registro con LitElement
523
-
524
- ```js
525
- import { LitElement, html, css } from 'lit';
526
- import { wuLit } from 'wu-framework/adapters/lit';
527
-
528
- class MyApp extends LitElement {
529
- static styles = css`
530
- :host { display: block; padding: 16px; }
531
- `;
532
-
533
- render() {
534
- return html`<h1>Hello from Lit!</h1>`;
535
- }
536
- }
537
-
538
- wuLit.register('my-app', MyApp);
539
- ```
540
-
541
- ### Con WuMixin
542
-
543
- ```js
544
- import { LitElement, html } from 'lit';
545
- import { WuMixin } from 'wu-framework/adapters/lit';
546
-
547
- class MyApp extends WuMixin(LitElement) {
548
- connectedCallback() {
549
- super.connectedCallback();
550
-
551
- // Usar eventos de Wu
552
- this.wuOn('user:login', (data) => {
553
- console.log('User logged in:', data);
554
- });
555
- }
556
-
557
- handleClick() {
558
- this.wuEmit('button:clicked', { id: 'my-button' });
559
- }
560
-
561
- render() {
562
- return html`
563
- <button @click=${this.handleClick}>Click me</button>
564
- `;
565
- }
314
+ )
566
315
  }
567
-
568
- wuLit.register('my-app', MyApp);
569
- ```
570
-
571
- ### Web Component Vanilla (sin Lit)
572
-
573
- ```js
574
- import { wuLit } from 'wu-framework/adapters/lit';
575
-
576
- class MyComponent extends HTMLElement {
577
- connectedCallback() {
578
- this.attachShadow({ mode: 'open' });
579
- this.shadowRoot.innerHTML = '<h1>Hello Web Component!</h1>';
580
- }
581
- }
582
-
583
- wuLit.registerWebComponent('my-component', MyComponent);
584
- ```
585
-
586
- ---
587
-
588
- ## 📦 Vanilla JS Adapter
589
-
590
- ### Registro con Objeto
591
-
592
- ```js
593
- import { wuVanilla } from 'wu-framework/adapters/vanilla';
594
-
595
- wuVanilla.register('my-app', {
596
- state: { count: 0 },
597
-
598
- render: (container, state) => {
599
- container.innerHTML = `
600
- <div>
601
- <h1>Count: ${state.count}</h1>
602
- <button id="increment">+</button>
603
- </div>
604
- `;
605
- container.querySelector('#increment').onclick = () => {
606
- state.count++;
607
- // Re-render manual
608
- };
609
- },
610
-
611
- destroy: (container) => {
612
- container.innerHTML = '';
613
- }
614
- });
615
316
  ```
616
317
 
617
- ### Registro con Clase
618
-
619
- ```js
620
- import { wuVanilla } from 'wu-framework/adapters/vanilla';
621
-
622
- class TodoApp {
623
- constructor(container) {
624
- this.container = container;
625
- this.todos = [];
626
- }
627
-
628
- render() {
629
- this.container.innerHTML = `
630
- <ul>
631
- ${this.todos.map(t => `<li>${t}</li>`).join('')}
632
- </ul>
633
- <input type="text" id="input" />
634
- <button id="add">Add</button>
635
- `;
636
-
637
- this.container.querySelector('#add').onclick = () => {
638
- const input = this.container.querySelector('#input');
639
- this.todos.push(input.value);
640
- this.render();
641
- };
642
- }
318
+ ### 4. Toast Container (Shell - escucha eventos de MFEs)
643
319
 
644
- destroy() {
645
- this.container.innerHTML = '';
646
- }
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'
647
329
  }
648
330
 
649
- wuVanilla.registerClass('todo-app', TodoApp);
650
- ```
331
+ export function ToastContainer() {
332
+ const [toasts, setToasts] = useState<Toast[]>([])
333
+ const { on } = useWuEvents()
651
334
 
652
- ### Registro con Template
653
-
654
- ```js
655
- import { wuVanilla } from 'wu-framework/adapters/vanilla';
656
-
657
- wuVanilla.registerTemplate('header', `
658
- <header>
659
- <h1>My Header</h1>
660
- <nav>
661
- <a href="/">Home</a>
662
- <a href="/about">About</a>
663
- </nav>
664
- </header>
665
- `);
666
-
667
- // Template dinámico
668
- wuVanilla.registerTemplate('greeting',
669
- (data) => `<h1>Hello, ${data.name}!</h1>`,
670
- { data: { name: 'World' } }
671
- );
672
- ```
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
+ }, [])
673
340
 
674
- ### Componente Reactivo
675
-
676
- ```js
677
- import { wuVanilla } from 'wu-framework/adapters/vanilla';
678
-
679
- const Counter = wuVanilla.createComponent({
680
- state: { count: 0 },
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])
681
349
 
682
- template: (state) => `
683
- <div>
684
- <h1>Count: ${state.count}</h1>
685
- <button data-action="increment">+</button>
686
- <button data-action="decrement">-</button>
350
+ 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
+ ))}
687
357
  </div>
688
- `,
689
-
690
- actions: {
691
- increment: (state) => ({ count: state.count + 1 }),
692
- decrement: (state) => ({ count: state.count - 1 })
693
- }
694
- });
695
-
696
- wuVanilla.register('counter', Counter);
358
+ )
359
+ }
697
360
  ```
698
361
 
699
362
  ---
700
363
 
701
- ## 📡 Event Bus
702
-
703
- Sistema de eventos para comunicación entre microfrontends con soporte para wildcards y replay.
364
+ ## 📡 Cross-MFE Communication
704
365
 
705
- ```js
706
- import { emit, on, once, off, replayEvents } from 'wu-framework';
366
+ ### Event Bus
707
367
 
708
- // Emitir evento
709
- emit('user:login', { userId: 123, name: 'John' });
368
+ ```ts
369
+ import { emit, on, once, off } from 'wu-framework'
710
370
 
711
- // Suscribirse a evento
712
- const unsubscribe = on('user:login', (event) => {
713
- console.log('User logged in:', event.data);
714
- });
371
+ // React MFE emite
372
+ emit('notification:new', { message: 'Hello!', type: 'success' })
715
373
 
716
- // Suscribirse con wildcards
717
- on('user:*', (event) => {
718
- console.log('User event:', event.name, event.data);
719
- });
374
+ // Vue MFE escucha
375
+ const unsubscribe = on('notification:new', (event) => {
376
+ console.log(event.data.message) // 'Hello!'
377
+ })
720
378
 
721
- // Suscribirse una sola vez
722
- once('app:ready', (event) => {
723
- console.log('App is ready!');
724
- });
379
+ // Wildcards - escuchar todos los eventos de notificación
380
+ on('notification:*', (event) => {
381
+ console.log('Event:', event.name, event.data)
382
+ })
725
383
 
726
- // Desuscribirse
727
- off('user:login', callback);
728
- unsubscribe(); // También funciona
384
+ // Una sola vez
385
+ once('app:ready', () => console.log('Ready!'))
729
386
 
730
- // Replay eventos del historial
731
- replayEvents('user:*', (event) => {
732
- console.log('Past event:', event);
733
- });
387
+ // Limpiar
388
+ unsubscribe()
734
389
  ```
735
390
 
736
- ---
737
-
738
- ## 🗄️ Store (State Management)
739
-
740
- Store de alto rendimiento con pattern matching.
741
-
742
- ```js
743
- import {
744
- getState,
745
- setState,
746
- onStateChange,
747
- batchState,
748
- clearState,
749
- getStoreMetrics
750
- } from 'wu-framework';
391
+ ### Store Reactivo
751
392
 
752
- // Establecer estado (dot notation)
753
- setState('user.name', 'John');
754
- setState('user.preferences.theme', 'dark');
393
+ ```ts
394
+ import { getState, setState, onStateChange, batchState } from 'wu-framework'
755
395
 
756
- // Obtener estado
757
- const name = getState('user.name'); // 'John'
758
- const user = getState('user'); // { name: 'John', preferences: { theme: 'dark' } }
396
+ // Vue MFE escribe
397
+ setState('notifications.count', 5)
398
+ setState('user.theme', 'dark')
759
399
 
760
- // Suscribirse a cambios
761
- const unsubscribe = onStateChange('user.name', (value, path) => {
762
- console.log(`${path} changed to:`, value);
763
- });
400
+ // React MFE lee
401
+ const count = getState('notifications.count') // 5
764
402
 
765
- // Suscribirse con wildcards
766
- onStateChange('user.*', (value, path) => {
767
- console.log(`User property changed: ${path} =`, value);
768
- });
403
+ // Angular MFE se suscribe
404
+ const unsub = onStateChange('notifications.*', (value, path) => {
405
+ console.log(`${path} changed:`, value)
406
+ })
769
407
 
770
- // Batch updates (más eficiente)
408
+ // Batch updates
771
409
  batchState({
772
- 'user.name': 'Jane',
773
- 'user.email': 'jane@example.com',
774
- 'settings.notifications': true
775
- });
776
-
777
- // Métricas de performance
778
- const metrics = getStoreMetrics();
779
- ```
780
-
781
- ---
782
-
783
- ## 🔌 Sistema de Plugins
784
-
785
- ```js
786
- import { usePlugin, createPlugin, uninstallPlugin } from 'wu-framework';
787
-
788
- const analyticsPlugin = createPlugin({
789
- name: 'analytics',
790
- permissions: ['events', 'store'],
791
-
792
- install: (api, options) => {
793
- api.on('app:mounted', (event) => {
794
- trackEvent('mount', event.data.appName);
795
- });
796
- },
797
-
798
- beforeMount: async (context) => {
799
- console.log('Before mount:', context.appName);
800
- },
801
-
802
- afterMount: async (context) => {
803
- console.log('Mounted in', context.mountTime, 'ms');
804
- }
805
- });
806
-
807
- usePlugin(analyticsPlugin, { trackingId: 'UA-123456' });
808
- ```
809
-
810
- ---
811
-
812
- ## 🪝 Lifecycle Hooks
813
-
814
- ```js
815
- import { useHook, createGuardHook, createTimedHook } from 'wu-framework';
816
-
817
- // Hook básico
818
- useHook('beforeMount', async (context, next) => {
819
- console.log('Before mounting:', context.appName);
820
- await next();
821
- }, { name: 'my-hook', priority: 10 });
822
-
823
- // Guard hook (puede cancelar)
824
- const authGuard = createGuardHook(async (ctx) => {
825
- return await isUserAuthenticated();
826
- });
827
- useHook('beforeMount', authGuard);
828
-
829
- // Hook con timeout
830
- const timedHook = createTimedHook(async (ctx) => {
831
- await slowOperation();
832
- }, 5000);
833
- ```
834
-
835
- ### Fases Disponibles
836
-
837
- | Fase | Descripción |
838
- |------|-------------|
839
- | `beforeInit` | Antes de inicializar framework |
840
- | `afterInit` | Después de inicializar |
841
- | `beforeLoad` | Antes de cargar una app |
842
- | `afterLoad` | Después de cargar |
843
- | `beforeMount` | Antes de montar |
844
- | `afterMount` | Después de montar |
845
- | `beforeUnmount` | Antes de desmontar |
846
- | `afterUnmount` | Después de desmontar |
847
-
848
- ---
849
-
850
- ## 🎯 Loading Strategies
851
-
852
- ```js
853
- await wu.init({
854
- apps: [
855
- { name: 'header', url: '/mfe/header', strategy: 'lazy' }, // Default - carga cuando se monta
856
- { name: 'sidebar', url: '/mfe/sidebar', strategy: 'eager' }, // Precarga inmediata
857
- { name: 'footer', url: '/mfe/footer', strategy: 'preload' }, // <link prefetch>
858
- { name: 'analytics', url: '/mfe/analytics', strategy: 'idle' } // requestIdleCallback
859
- ]
860
- });
861
- ```
862
-
863
- | Estrategia | Descripción | Uso recomendado |
864
- |------------|-------------|-----------------|
865
- | `lazy` | Carga cuando se monta (default) | Contenido below-the-fold |
866
- | `eager` | Precarga inmediata | Componentes críticos |
867
- | `preload` | Usa `<link rel="prefetch">` | Navegación anticipada |
868
- | `idle` | Usa `requestIdleCallback` | Analytics, features secundarias |
869
-
870
- ---
871
-
872
- ## ⚡ Performance Monitoring
873
-
874
- ```js
875
- import {
876
- startMeasure,
877
- endMeasure,
878
- getPerformanceMetrics,
879
- generatePerformanceReport
880
- } from 'wu-framework';
881
-
882
- // Medición personalizada
883
- startMeasure('data-fetch', 'my-app');
884
- await fetchData();
885
- const duration = endMeasure('data-fetch', 'my-app');
886
-
887
- // Reporte completo
888
- const report = generatePerformanceReport();
889
- ```
890
-
891
- ---
892
-
893
- ## 🛡️ Error Handling
894
-
895
- ```js
896
- import { registerErrorHandler, configureErrorBoundary } from 'wu-framework';
897
-
898
- registerErrorHandler({
899
- name: 'api-error',
900
- canHandle: (error) => error.message.includes('API'),
901
- handle: async (error, context) => {
902
- if (context.retryCount < 3) {
903
- return { recovered: true, action: 'retry' };
904
- }
905
- return { recovered: false, action: 'fallback' };
906
- }
907
- });
908
-
909
- configureErrorBoundary({
910
- maxRetries: 3,
911
- retryDelay: 1000,
912
- showErrorUI: true
913
- });
914
- ```
915
-
916
- ---
917
-
918
- ## 🎯 API Simplificada (wu.app)
919
-
920
- ```js
921
- import { wu } from 'wu-framework';
922
-
923
- // URL puede ser localhost (dev) o CDN (prod)
924
- const header = wu.app('header', {
925
- url: 'http://localhost:3001', // o 'https://cdn.mycompany.com/mfe/header'
926
- container: '#header-container'
927
- });
928
-
929
- await header.mount();
930
- console.log(header.isMounted); // true
931
-
932
- await header.unmount();
933
- await header.remount();
934
- await header.reload(); // Limpia cache
935
-
936
- const health = await header.verify();
937
- await header.destroy();
410
+ 'user.name': 'John',
411
+ 'notifications.count': 0
412
+ })
938
413
  ```
939
414
 
940
- ---
941
-
942
- ## 🚀 Deployment
943
-
944
- ### Estructura de Producción
415
+ ### Hooks por Framework
945
416
 
946
- Cada microfrontend se despliega de forma independiente:
417
+ **React:**
418
+ ```tsx
419
+ import { createUseWuEvents, createUseWuStore } from 'wu-framework/adapters/react'
947
420
 
948
- ```
949
- https://cdn.mycompany.com/
950
- ├── mfe/
951
- │ ├── header/
952
- │ │ ├── wu.json # Manifest
953
- │ │ ├── index.js # Entry point
954
- │ │ └── assets/
955
- │ ├── sidebar/
956
- │ │ ├── wu.json
957
- │ │ ├── index.js
958
- │ │ └── assets/
959
- │ └── content/
960
- │ ├── wu.json
961
- │ ├── index.js
962
- │ └── assets/
963
- ```
421
+ const useWuEvents = createUseWuEvents(React)
422
+ const useWuStore = createUseWuStore(React)
964
423
 
965
- ### Configuración por Entorno
966
-
967
- ```js
968
- // config.js
969
- const config = {
970
- development: {
971
- header: 'http://localhost:3001',
972
- sidebar: 'http://localhost:3002',
973
- content: 'http://localhost:3003'
974
- },
975
- staging: {
976
- header: 'https://staging-cdn.mycompany.com/mfe/header',
977
- sidebar: 'https://staging-cdn.mycompany.com/mfe/sidebar',
978
- content: 'https://staging-cdn.mycompany.com/mfe/content'
979
- },
980
- production: {
981
- header: 'https://cdn.mycompany.com/mfe/header',
982
- sidebar: 'https://cdn.mycompany.com/mfe/sidebar',
983
- content: 'https://cdn.mycompany.com/mfe/content'
984
- }
985
- };
986
-
987
- const env = process.env.NODE_ENV || 'development';
988
- const urls = config[env];
989
-
990
- await wu.init({
991
- apps: [
992
- { name: 'header', url: urls.header },
993
- { name: 'sidebar', url: urls.sidebar },
994
- { name: 'content', url: urls.content }
995
- ]
996
- });
997
- ```
998
-
999
- ### CORS Configuration
424
+ function MyComponent() {
425
+ const { emit, on } = useWuEvents()
426
+ const { state, setState } = useWuStore('notifications')
1000
427
 
1001
- Los microfrontends deben permitir CORS desde el shell:
428
+ useEffect(() => {
429
+ return on('user:login', (e) => console.log(e.data))
430
+ }, [])
1002
431
 
1003
- ```nginx
1004
- # nginx.conf para CDN
1005
- location /mfe/ {
1006
- add_header Access-Control-Allow-Origin *;
1007
- add_header Access-Control-Allow-Methods "GET, OPTIONS";
1008
- add_header Access-Control-Allow-Headers "Content-Type";
432
+ return <span>Count: {state?.count || 0}</span>
1009
433
  }
1010
434
  ```
1011
435
 
1012
- ### Versionado
436
+ **Vue:**
437
+ ```vue
438
+ <script setup>
439
+ import { useWuEvents, useWuStore } from 'wu-framework/adapters/vue'
1013
440
 
1014
- ```json
1015
- // wu.json con versión
1016
- {
1017
- "name": "header",
1018
- "version": "1.2.0",
1019
- "entry": "index.js"
1020
- }
1021
- ```
441
+ const { emit, on } = useWuEvents()
442
+ const { state, setState } = useWuStore('cart')
1022
443
 
1023
- ```js
1024
- // Shell con versiones específicas
1025
- await wu.init({
1026
- apps: [
1027
- { name: 'header', url: 'https://cdn.mycompany.com/mfe/header/v1.2.0' },
1028
- { name: 'sidebar', url: 'https://cdn.mycompany.com/mfe/sidebar/v2.0.0' }
1029
- ]
1030
- });
444
+ onMounted(() => {
445
+ on('cart:updated', (data) => console.log(data))
446
+ })
447
+ </script>
1031
448
  ```
1032
449
 
1033
450
  ---
@@ -1036,106 +453,93 @@ await wu.init({
1036
453
 
1037
454
  ```
1038
455
  ┌─────────────────────────────────────────────────────────────┐
1039
- HOST APPLICATION
456
+ SHELL (React)
457
+ │ ┌──────────────────────────────────────────────────────┐ │
458
+ │ │ ToastContainer (escucha notification:new) │ │
459
+ │ └──────────────────────────────────────────────────────┘ │
1040
460
  ├─────────────────────────────────────────────────────────────┤
1041
- │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐
1042
- │ │ #shadow-root │ │ #shadow-root #shadow-root│ │
1043
- │ │ ┌───────────┐ │ ┌───────────┐ ┌─────────┐ │ │
1044
- │ │ │ Header │ │ │ │ Sidebar │ │ │ Content │ │ │
1045
- │ │ │ (React) │ │ │ │ (Vue) │ │ │(Angular)│ │ │
1046
- │ │ └───────────┘ │ │ └───────────┘ │ │ └─────────┘ │ │
1047
- │ │ CSS Isolated │ │ CSS Isolated │ │ CSS Isolated│ │
1048
- │ │ JS Sandboxed │ JS Sandboxed │ │ JS Sandboxed
1049
- └─────────────────┘ └─────────────────┘ └─────────────┘
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
+ │ └─────────────────┘ └─────────────────────┘ │
1050
471
  ├─────────────────────────────────────────────────────────────┤
1051
- │ WU FRAMEWORK CORE
1052
- │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐
1053
- │ │ EventBus │ │ Store │ │ Plugins │ │ Sandbox Pool │ │
1054
- │ └──────────┘ └──────────┘ └──────────┘ └────────────────┘
472
+ │ WU FRAMEWORK CORE
473
+ │ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────────┐
474
+ │ │ EventBus │ │ Store │ │StyleBridge│ │ Sandbox Pool │ │
475
+ │ └──────────┘ └──────────┘ └───────────┘ └──────────────┘
1055
476
  └─────────────────────────────────────────────────────────────┘
1056
477
  ```
1057
478
 
1058
- ---
1059
-
1060
- ## 📋 API Reference
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`
1061
485
 
1062
- ### Core
486
+ ---
1063
487
 
1064
- ```js
1065
- import { wu, init, mount, unmount, destroy, getStats } from 'wu-framework';
1066
- ```
488
+ ## 🎨 Adapters
1067
489
 
1068
- ### Event Bus
1069
-
1070
- ```js
1071
- import { emit, on, once, off, replayEvents, getEventBusStats } from 'wu-framework';
1072
- ```
1073
-
1074
- ### Store
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)` |
1075
500
 
1076
- ```js
1077
- import { getState, setState, onStateChange, batchState, clearState } from 'wu-framework';
1078
- ```
501
+ ---
1079
502
 
1080
- ### Plugins & Hooks
503
+ ## ⚙️ Core Systems
1081
504
 
1082
- ```js
1083
- import { usePlugin, createPlugin, useHook, removeHook } from 'wu-framework';
1084
- ```
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 |
1085
515
 
1086
- ### Performance & Errors
516
+ ---
1087
517
 
1088
- ```js
1089
- import { startMeasure, endMeasure, generatePerformanceReport } from 'wu-framework';
1090
- import { registerErrorHandler, configureErrorBoundary } from 'wu-framework';
1091
- ```
518
+ ## 📋 API Reference
1092
519
 
1093
- ### Adapters
1094
-
1095
- ```js
1096
- import { wuReact } from 'wu-framework/adapters/react';
1097
- import { wuVue } from 'wu-framework/adapters/vue';
1098
- import { wuAngular } from 'wu-framework/adapters/angular';
1099
- import { wuSvelte } from 'wu-framework/adapters/svelte';
1100
- import { wuPreact } from 'wu-framework/adapters/preact';
1101
- import { wuSolid } from 'wu-framework/adapters/solid';
1102
- import { wuLit } from 'wu-framework/adapters/lit';
1103
- import { wuVanilla } from 'wu-framework/adapters/vanilla';
1104
- ```
520
+ ```ts
521
+ // Core
522
+ import { wu, init, mount, unmount, destroy } from 'wu-framework'
1105
523
 
1106
- ### Utilities
524
+ // Events
525
+ import { emit, on, once, off, replayEvents } from 'wu-framework'
1107
526
 
1108
- ```js
1109
- import { presets, dev, events } from 'wu-framework';
527
+ // Store
528
+ import { getState, setState, onStateChange, batchState } from 'wu-framework'
1110
529
 
1111
- // Presets
1112
- await wu.init(presets.development([{ name: 'app', port: 3001 }]));
1113
- await wu.init(presets.production([{ name: 'app', url: 'https://...' }]));
530
+ // Performance
531
+ import { startMeasure, endMeasure, generatePerformanceReport } from 'wu-framework'
1114
532
 
1115
- // Dev tools
1116
- dev.enableDebug();
1117
- dev.inspect();
1118
- await dev.reload('app');
533
+ // Plugins
534
+ import { usePlugin, createPlugin, useHook } from 'wu-framework'
1119
535
 
1120
- // Silenciar logs
1121
- wu.silence();
1122
- wu.verbose();
536
+ // Adapters
537
+ import { wuReact } from 'wu-framework/adapters/react'
538
+ import { wuVue } from 'wu-framework/adapters/vue'
1123
539
  ```
1124
540
 
1125
541
  ---
1126
542
 
1127
- ## 🤝 Contributing
1128
-
1129
- ¡Las contribuciones son bienvenidas!
1130
-
1131
- 1. **Fork** el repositorio
1132
- 2. **Crear** branch (`git checkout -b feature/amazing-feature`)
1133
- 3. **Commit** tus cambios (`git commit -m 'Add amazing feature'`)
1134
- 4. **Push** al branch (`git push origin feature/amazing-feature`)
1135
- 5. **Abrir** un Pull Request
1136
-
1137
- ---
1138
-
1139
543
  ## 📄 License
1140
544
 
1141
545
  MIT License - Copyright (c) 2025 Wu Framework Team
@@ -1145,5 +549,5 @@ MIT License - Copyright (c) 2025 Wu Framework Team
1145
549
  <p align="center">
1146
550
  <b>🚀 Wu Framework - Universal Microfrontends Made Simple</b>
1147
551
  <br><br>
1148
- <i>Zero dependencies8 FrameworksShadow DOM Proxy Sandbox Self-Healing</i>
552
+ <i>Shadow DOM4 CSS Isolation Modes Cross-MFE Events & StoreZero Config</i>
1149
553
  </p>