wu-framework 1.1.0 → 1.1.1
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 +210 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,26 +46,36 @@ Wu Framework incluye **adapters nativos** para los frameworks más populares:
|
|
|
46
46
|
|
|
47
47
|
## 🔥 Quick Start
|
|
48
48
|
|
|
49
|
-
### 1.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
49
|
+
### 1. Micro App: Crear `wu.json`
|
|
50
|
+
|
|
51
|
+
Cada microfrontend necesita un archivo `wu.json` en su raíz:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"name": "header",
|
|
56
|
+
"entry": "index.js",
|
|
57
|
+
"wu": {
|
|
58
|
+
"exports": {
|
|
59
|
+
"NavBar": "components/NavBar.js",
|
|
60
|
+
"UserMenu": "components/UserMenu.js"
|
|
61
|
+
},
|
|
62
|
+
"imports": [],
|
|
63
|
+
"routes": ["/", "/home"],
|
|
64
|
+
"permissions": ["events", "store"]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
|
|
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)
|
|
69
79
|
|
|
70
80
|
**React:**
|
|
71
81
|
```tsx
|
|
@@ -93,6 +103,70 @@ wuAngular.register('content', AppModule);
|
|
|
93
103
|
|
|
94
104
|
**¡Eso es todo!** El adapter se encarga de todo: detección de contexto, modo standalone, cleanup automático.
|
|
95
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
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
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
|
+
```
|
|
169
|
+
|
|
96
170
|
---
|
|
97
171
|
|
|
98
172
|
## ⚛️ React Adapter
|
|
@@ -155,16 +229,20 @@ import { createWuSlot } from 'wu-framework/adapters/react';
|
|
|
155
229
|
|
|
156
230
|
const WuSlot = createWuSlot(React);
|
|
157
231
|
|
|
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';
|
|
235
|
+
|
|
158
236
|
function Shell() {
|
|
159
237
|
return (
|
|
160
238
|
<div>
|
|
161
239
|
<WuSlot
|
|
162
240
|
name="header"
|
|
163
|
-
url=
|
|
241
|
+
url={HEADER_URL}
|
|
164
242
|
onLoad={() => console.log('Header loaded!')}
|
|
165
243
|
onError={(err) => console.error(err)}
|
|
166
244
|
/>
|
|
167
|
-
<WuSlot name="content" url=
|
|
245
|
+
<WuSlot name="content" url={CONTENT_URL} />
|
|
168
246
|
</div>
|
|
169
247
|
);
|
|
170
248
|
}
|
|
@@ -229,17 +307,21 @@ onUnmounted(() => cleanup());
|
|
|
229
307
|
```vue
|
|
230
308
|
<script setup>
|
|
231
309
|
import { WuSlot } from 'wu-framework/adapters/vue';
|
|
310
|
+
|
|
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';
|
|
232
314
|
</script>
|
|
233
315
|
|
|
234
316
|
<template>
|
|
235
317
|
<div>
|
|
236
318
|
<WuSlot
|
|
237
319
|
name="header"
|
|
238
|
-
url="
|
|
320
|
+
:url="headerUrl"
|
|
239
321
|
@load="onLoad"
|
|
240
322
|
@error="onError"
|
|
241
323
|
/>
|
|
242
|
-
<WuSlot name="sidebar" url="
|
|
324
|
+
<WuSlot name="sidebar" :url="sidebarUrl" />
|
|
243
325
|
</div>
|
|
244
326
|
</template>
|
|
245
327
|
```
|
|
@@ -770,14 +852,21 @@ const timedHook = createTimedHook(async (ctx) => {
|
|
|
770
852
|
```js
|
|
771
853
|
await wu.init({
|
|
772
854
|
apps: [
|
|
773
|
-
{ name: 'header', url: '
|
|
774
|
-
{ name: 'sidebar', url: '
|
|
775
|
-
{ name: 'footer', url: '
|
|
776
|
-
{ name: 'analytics', url: '
|
|
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
|
|
777
859
|
]
|
|
778
860
|
});
|
|
779
861
|
```
|
|
780
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
|
+
|
|
781
870
|
---
|
|
782
871
|
|
|
783
872
|
## ⚡ Performance Monitoring
|
|
@@ -831,8 +920,9 @@ configureErrorBoundary({
|
|
|
831
920
|
```js
|
|
832
921
|
import { wu } from 'wu-framework';
|
|
833
922
|
|
|
923
|
+
// URL puede ser localhost (dev) o CDN (prod)
|
|
834
924
|
const header = wu.app('header', {
|
|
835
|
-
url: 'http://localhost:3001',
|
|
925
|
+
url: 'http://localhost:3001', // o 'https://cdn.mycompany.com/mfe/header'
|
|
836
926
|
container: '#header-container'
|
|
837
927
|
});
|
|
838
928
|
|
|
@@ -849,6 +939,99 @@ await header.destroy();
|
|
|
849
939
|
|
|
850
940
|
---
|
|
851
941
|
|
|
942
|
+
## 🚀 Deployment
|
|
943
|
+
|
|
944
|
+
### Estructura de Producción
|
|
945
|
+
|
|
946
|
+
Cada microfrontend se despliega de forma independiente:
|
|
947
|
+
|
|
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
|
+
```
|
|
964
|
+
|
|
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
|
|
1000
|
+
|
|
1001
|
+
Los microfrontends deben permitir CORS desde el shell:
|
|
1002
|
+
|
|
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";
|
|
1009
|
+
}
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
### Versionado
|
|
1013
|
+
|
|
1014
|
+
```json
|
|
1015
|
+
// wu.json con versión
|
|
1016
|
+
{
|
|
1017
|
+
"name": "header",
|
|
1018
|
+
"version": "1.2.0",
|
|
1019
|
+
"entry": "index.js"
|
|
1020
|
+
}
|
|
1021
|
+
```
|
|
1022
|
+
|
|
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
|
+
});
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
---
|
|
1034
|
+
|
|
852
1035
|
## 🏗️ Arquitectura
|
|
853
1036
|
|
|
854
1037
|
```
|