wu-framework 1.1.3 → 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 +1115 -395
- package/dist/wu-framework.protected.js +24 -0
- package/package.json +32 -6
- package/scripts/build-protected.js +366 -0
- package/scripts/build.js +212 -0
- package/scripts/rollup-plugin-hex.js +143 -0
- package/src/adapters/angular.js +171 -0
- package/src/adapters/vue.js +41 -0
- package/src/core/wu-core.js +14 -32
- package/src/core/wu-manifest.js +13 -31
- package/src/core/wu-sandbox.js +259 -18
- package/src/core/wu-style-bridge.js +118 -312
package/src/core/wu-sandbox.js
CHANGED
|
@@ -56,9 +56,10 @@ export class WuSandbox {
|
|
|
56
56
|
* 🔧 SMART SANDBOX: Advanced Shadow DOM creation with error recovery
|
|
57
57
|
* @param {string} appName - Nombre de la aplicación
|
|
58
58
|
* @param {HTMLElement} hostContainer - Contenedor host
|
|
59
|
+
* @param {Object} options - Opciones adicionales (styleMode, manifest, etc.)
|
|
59
60
|
* @returns {Object} Sandbox con shadow root y container
|
|
60
61
|
*/
|
|
61
|
-
create(appName, hostContainer) {
|
|
62
|
+
create(appName, hostContainer, options = {}) {
|
|
62
63
|
console.log(`[WuSandbox] 🔨 Creating sandbox for: ${appName}`);
|
|
63
64
|
|
|
64
65
|
try {
|
|
@@ -109,6 +110,9 @@ export class WuSandbox {
|
|
|
109
110
|
const jsSandbox = this.createAdvancedJSSandbox(appName);
|
|
110
111
|
const jsProxy = jsSandbox.activate(); // Activar sandbox y obtener proxy
|
|
111
112
|
|
|
113
|
+
// Verificar styleMode del manifest antes de inyectar estilos
|
|
114
|
+
const styleMode = options.styleMode || options.manifest?.styleMode;
|
|
115
|
+
|
|
112
116
|
const sandbox = {
|
|
113
117
|
appName,
|
|
114
118
|
shadowRoot,
|
|
@@ -118,28 +122,124 @@ export class WuSandbox {
|
|
|
118
122
|
jsSandbox, // NUEVO: ProxySandbox o SnapshotSandbox
|
|
119
123
|
jsProxy, // NUEVO: Proxy para ejecutar scripts
|
|
120
124
|
styles: baseStyles,
|
|
125
|
+
styleMode, // Guardar styleMode para uso futuro
|
|
126
|
+
manifest: options.manifest, // Guardar manifest completo
|
|
121
127
|
created: Date.now(),
|
|
122
128
|
sandbox_state: 'stable',
|
|
123
129
|
recovery_count: 0
|
|
124
130
|
};
|
|
125
131
|
|
|
126
|
-
// 🎨 INJECT
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
// 🎨 INJECT STYLES: Comportamiento según styleMode
|
|
133
|
+
// - "shared": Inyecta todos los estilos del documento padre
|
|
134
|
+
// - "isolated": NO inyecta estilos externos (encapsulamiento nativo Shadow DOM)
|
|
135
|
+
// - "fully-isolated": Inyecta SOLO estilos propios de la app
|
|
136
|
+
|
|
137
|
+
if (styleMode === 'isolated') {
|
|
138
|
+
// 🔒 MODO ISOLATED: Encapsulamiento nativo del Shadow DOM
|
|
139
|
+
// No se inyectan estilos externos - la app debe manejar sus propios estilos
|
|
140
|
+
console.log(`[WuSandbox] 🔒 Style mode "isolated" for ${appName}, using native Shadow DOM encapsulation`);
|
|
141
|
+
sandbox.stylesReady = Promise.resolve(0);
|
|
142
|
+
// No configurar observer de estilos - la app es responsable de sus propios estilos
|
|
143
|
+
|
|
144
|
+
} else if (styleMode === 'fully-isolated') {
|
|
145
|
+
console.log(`[WuSandbox] 🛡️ Style mode "fully-isolated" detected for ${appName}, using enhanced style injection`);
|
|
146
|
+
// Registrar esta app como fully-isolated en el style bridge para filtrar sus estilos
|
|
147
|
+
const appUrl = options.appUrl || (options.manifest?.name ? `/${options.manifest.name}/` : `/${appName}/`);
|
|
148
|
+
this.styleBridge.registerFullyIsolatedApp(appName, appUrl);
|
|
149
|
+
|
|
150
|
+
// Guardar appUrl en sandbox para uso en reinjectStyles
|
|
151
|
+
sandbox.appUrl = appUrl;
|
|
152
|
+
|
|
153
|
+
// Para fully-isolated, inyectar SOLO los estilos propios de la app en su Shadow DOM
|
|
154
|
+
// Guardamos referencia a this para usar en el observer
|
|
155
|
+
const self = this;
|
|
156
|
+
|
|
157
|
+
sandbox.stylesReady = new Promise((resolve) => {
|
|
158
|
+
let resolved = false;
|
|
159
|
+
|
|
160
|
+
const tryInject = async () => {
|
|
161
|
+
const count = await self.injectOwnStylesToShadow(shadowRoot, appName, appUrl);
|
|
162
|
+
|
|
163
|
+
if (count > 0) {
|
|
164
|
+
console.log(`[WuSandbox] 🎨 Injected ${count} own styles for ${appName} (fully-isolated)`);
|
|
165
|
+
if (!resolved) {
|
|
166
|
+
resolved = true;
|
|
167
|
+
resolve(count);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return count;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Usar MutationObserver PERSISTENTE para detectar cuando se inyectan estilos del app
|
|
175
|
+
console.log(`[WuSandbox] 👀 Setting up style observer for ${appName} (fully-isolated)`);
|
|
176
|
+
const observer = new MutationObserver((mutations) => {
|
|
177
|
+
let newStyleCount = 0;
|
|
178
|
+
for (const m of mutations) {
|
|
179
|
+
if (m.type === 'childList') {
|
|
180
|
+
for (const n of m.addedNodes) {
|
|
181
|
+
if (n.nodeName === 'STYLE' || n.nodeName === 'LINK') {
|
|
182
|
+
newStyleCount++;
|
|
183
|
+
const viteId = n.getAttribute ? n.getAttribute('data-vite-dev-id') : null;
|
|
184
|
+
if (viteId && viteId.toLowerCase().includes(appName.toLowerCase())) {
|
|
185
|
+
console.log(`[WuSandbox] 🆕 New ${appName} style detected: ${viteId.split('/').pop()}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (newStyleCount > 0) {
|
|
192
|
+
console.log(`[WuSandbox] 🔄 ${newStyleCount} new styles detected in head, checking for ${appName}...`);
|
|
193
|
+
tryInject();
|
|
194
|
+
}
|
|
135
195
|
});
|
|
196
|
+
|
|
197
|
+
// Observar cambios en el head DE FORMA PERSISTENTE
|
|
198
|
+
observer.observe(document.head, {
|
|
199
|
+
childList: true,
|
|
200
|
+
subtree: true
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Guardar referencia al observer para poder desconectarlo cuando se desmonte la app
|
|
204
|
+
sandbox.styleObserver = observer;
|
|
205
|
+
|
|
206
|
+
// Intento inicial con pequeño delay para que Vite procese los imports
|
|
207
|
+
setTimeout(async () => {
|
|
208
|
+
const count = await tryInject();
|
|
209
|
+
// Si después de 3 segundos no hay estilos, usar fallback
|
|
210
|
+
if (!resolved) {
|
|
211
|
+
setTimeout(() => {
|
|
212
|
+
if (!resolved) {
|
|
213
|
+
console.warn(`[WuSandbox] ⚠️ No own styles found for ${appName} after timeout, using FALLBACK`);
|
|
214
|
+
const fallbackCount = self.injectAllStylesToShadow(shadowRoot, appName);
|
|
215
|
+
console.log(`[WuSandbox] 🎨 FALLBACK: Injected ${fallbackCount} styles for ${appName}`);
|
|
216
|
+
resolved = true;
|
|
217
|
+
resolve(fallbackCount);
|
|
218
|
+
}
|
|
219
|
+
}, 3000);
|
|
220
|
+
}
|
|
221
|
+
}, 50);
|
|
136
222
|
});
|
|
223
|
+
} else {
|
|
224
|
+
// 🌐 MODO SHARED (default): Inyectar todos los estilos compartidos del documento
|
|
225
|
+
console.log(`[WuSandbox] 🌐 Style mode "shared" for ${appName}, injecting all shared styles...`);
|
|
226
|
+
sandbox.stylesReady = this.styleBridge.injectStylesIntoShadow(shadowRoot, appName, styleMode).then(count => {
|
|
227
|
+
console.log(`[WuSandbox] 🎨 Shared ${count} styles with ${appName}`);
|
|
228
|
+
|
|
229
|
+
// 🔄 Observar cambios dinámicos de estilos (HMR de Vite)
|
|
230
|
+
this.styleBridge.observeStyleChanges(() => {
|
|
231
|
+
console.log(`[WuSandbox] 🔄 Reinjecting styles for ${appName} due to changes`);
|
|
232
|
+
this.styleBridge.injectStylesIntoShadow(shadowRoot, appName, styleMode).catch(err => {
|
|
233
|
+
console.warn(`[WuSandbox] ⚠️ Failed to reinject styles:`, err);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
137
236
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
237
|
+
return count;
|
|
238
|
+
}).catch(error => {
|
|
239
|
+
console.warn(`[WuSandbox] ⚠️ Failed to inject styles:`, error);
|
|
240
|
+
return 0;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
143
243
|
|
|
144
244
|
// 📊 Register in sandbox registry
|
|
145
245
|
this.sandboxes.set(appName, sandbox);
|
|
@@ -710,11 +810,152 @@ export class WuSandbox {
|
|
|
710
810
|
return;
|
|
711
811
|
}
|
|
712
812
|
|
|
713
|
-
|
|
813
|
+
const styleMode = sandbox.styleMode;
|
|
814
|
+
|
|
815
|
+
// 🔒 MODO ISOLATED: No reinyectar estilos - la app maneja sus propios estilos
|
|
816
|
+
if (styleMode === 'isolated') {
|
|
817
|
+
console.log(`[WuSandbox] 🔒 Skipping reinject for ${appName} (isolated mode - app manages own styles)`);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// 🛡️ MODO FULLY-ISOLATED: Reinyectar SOLO estilos propios
|
|
822
|
+
if (styleMode === 'fully-isolated') {
|
|
823
|
+
console.log(`[WuSandbox] 🔄 Reinjecting OWN styles for ${appName} (fully-isolated)...`);
|
|
824
|
+
const appUrl = sandbox.appUrl || sandbox.manifest?.name ? `/${sandbox.manifest.name}/` : `/${appName}/`;
|
|
825
|
+
const count = await this.injectOwnStylesToShadow(sandbox.shadowRoot, appName, appUrl);
|
|
826
|
+
console.log(`[WuSandbox] ✅ Reinjected ${count} own styles for ${appName}`);
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// 🌐 MODO SHARED: Reinyectar todos los estilos compartidos
|
|
831
|
+
console.log(`[WuSandbox] 🔄 Reinjecting shared styles for ${appName}...`);
|
|
714
832
|
const count = await this.styleBridge.injectStylesIntoShadow(
|
|
715
833
|
sandbox.shadowRoot,
|
|
716
|
-
appName
|
|
834
|
+
appName,
|
|
835
|
+
styleMode
|
|
717
836
|
);
|
|
718
|
-
console.log(`[WuSandbox] ✅ Reinjected ${count} styles`);
|
|
837
|
+
console.log(`[WuSandbox] ✅ Reinjected ${count} shared styles`);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* 🎨 INYECTAR ESTILOS PROPIOS: Inyecta SOLO los estilos propios de una app en su Shadow DOM
|
|
842
|
+
* Usado para apps en modo fully-isolated
|
|
843
|
+
* @param {ShadowRoot} shadowRoot - Shadow DOM donde inyectar
|
|
844
|
+
* @param {string} appName - Nombre de la app
|
|
845
|
+
* @param {string} appUrl - URL base de la app
|
|
846
|
+
* @returns {Promise<number>} Número de estilos inyectados
|
|
847
|
+
*/
|
|
848
|
+
async injectOwnStylesToShadow(shadowRoot, appName, appUrl) {
|
|
849
|
+
if (!shadowRoot) return 0;
|
|
850
|
+
|
|
851
|
+
let injectedCount = 0;
|
|
852
|
+
|
|
853
|
+
// Buscar TODOS los estilos en el head
|
|
854
|
+
const allStyles = document.querySelectorAll('style');
|
|
855
|
+
const normalizedAppName = appName.toLowerCase();
|
|
856
|
+
|
|
857
|
+
// Patrones para detectar estilos de esta app (Windows y Unix paths)
|
|
858
|
+
// IMPORTANTE: Debe coincidir SOLO con packages/appName/ al inicio del path del paquete
|
|
859
|
+
// NO debe coincidir con packages/shell/src/components/learning/ (eso es del shell)
|
|
860
|
+
const appPatterns = [
|
|
861
|
+
// Patrón específico: packages/learning/src o packages\learning\src
|
|
862
|
+
// El src/ es clave para asegurar que es el MFE, no un subdirectorio de otro package
|
|
863
|
+
new RegExp(`packages[/\\\\]${normalizedAppName}[/\\\\]src[/\\\\]`, 'i')
|
|
864
|
+
];
|
|
865
|
+
|
|
866
|
+
console.log(`[WuSandbox] 🔍 Searching own styles for ${appName}, found ${allStyles.length} style tags in head`);
|
|
867
|
+
|
|
868
|
+
// Log para debug: mostrar estilos que contienen el nombre de la app
|
|
869
|
+
let matchingCount = 0;
|
|
870
|
+
for (const s of allStyles) {
|
|
871
|
+
const vid = s.getAttribute('data-vite-dev-id') || '';
|
|
872
|
+
if (vid.toLowerCase().includes(normalizedAppName)) {
|
|
873
|
+
matchingCount++;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
if (matchingCount > 0) {
|
|
877
|
+
console.log(`[WuSandbox] 📋 Found ${matchingCount} styles potentially matching ${appName}`);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
for (const style of allStyles) {
|
|
881
|
+
// NO saltar basándose en data-wu-injected del head - eso se pone en los clones del shadow DOM
|
|
882
|
+
|
|
883
|
+
const viteId = style.getAttribute('data-vite-dev-id') || '';
|
|
884
|
+
const normalizedViteId = viteId.replace(/\\/g, '/').toLowerCase();
|
|
885
|
+
|
|
886
|
+
// Verificar si el estilo pertenece a esta app
|
|
887
|
+
let belongsToApp = false;
|
|
888
|
+
|
|
889
|
+
// 1. Por data-vite-dev-id (la forma más confiable)
|
|
890
|
+
if (viteId) {
|
|
891
|
+
// Revisar si el path contiene packages/appName/
|
|
892
|
+
for (const pattern of appPatterns) {
|
|
893
|
+
if (pattern instanceof RegExp) {
|
|
894
|
+
if (pattern.test(viteId)) {
|
|
895
|
+
belongsToApp = true;
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
} else {
|
|
899
|
+
if (normalizedViteId.includes(pattern.toLowerCase())) {
|
|
900
|
+
belongsToApp = true;
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
if (belongsToApp) {
|
|
908
|
+
// Verificar si ya existe en el Shadow DOM
|
|
909
|
+
const existingStyle = shadowRoot.querySelector(`style[data-vite-dev-id="${viteId}"]`);
|
|
910
|
+
|
|
911
|
+
if (!existingStyle) {
|
|
912
|
+
const clonedStyle = style.cloneNode(true);
|
|
913
|
+
clonedStyle.setAttribute('data-wu-injected', 'true');
|
|
914
|
+
shadowRoot.insertBefore(clonedStyle, shadowRoot.firstChild);
|
|
915
|
+
injectedCount++;
|
|
916
|
+
const styleName = viteId.substring(viteId.lastIndexOf('/') + 1) || viteId.substring(viteId.lastIndexOf('\\') + 1);
|
|
917
|
+
console.log(`[WuSandbox] ✅ Injected own style for ${appName}: ${styleName}`);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
console.log(`[WuSandbox] 🎨 Total own styles injected for ${appName}: ${injectedCount}`);
|
|
923
|
+
return injectedCount;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* 🎨 FALLBACK: Inyectar estilos que contengan el nombre de la app
|
|
928
|
+
* Usado como último recurso cuando no se encuentran los estilos con el patrón exacto
|
|
929
|
+
* @param {ShadowRoot} shadowRoot - Shadow DOM donde inyectar
|
|
930
|
+
* @param {string} appName - Nombre de la app (para logging)
|
|
931
|
+
* @returns {number} Número de estilos inyectados
|
|
932
|
+
*/
|
|
933
|
+
injectAllStylesToShadow(shadowRoot, appName) {
|
|
934
|
+
if (!shadowRoot) return 0;
|
|
935
|
+
|
|
936
|
+
let injectedCount = 0;
|
|
937
|
+
const normalizedAppName = appName.toLowerCase();
|
|
938
|
+
|
|
939
|
+
// Inyectar estilos que contengan el nombre de la app en su vite-id
|
|
940
|
+
const allStyles = document.querySelectorAll('style');
|
|
941
|
+
for (const style of allStyles) {
|
|
942
|
+
const viteId = style.getAttribute('data-vite-dev-id') || '';
|
|
943
|
+
|
|
944
|
+
// Solo inyectar si contiene el nombre de la app
|
|
945
|
+
if (!viteId.toLowerCase().includes(normalizedAppName)) continue;
|
|
946
|
+
|
|
947
|
+
// Verificar si ya existe en el shadow DOM
|
|
948
|
+
if (shadowRoot.querySelector(`style[data-vite-dev-id="${viteId}"]`)) continue;
|
|
949
|
+
|
|
950
|
+
const clonedStyle = style.cloneNode(true);
|
|
951
|
+
clonedStyle.setAttribute('data-wu-fallback', 'true');
|
|
952
|
+
shadowRoot.insertBefore(clonedStyle, shadowRoot.firstChild);
|
|
953
|
+
injectedCount++;
|
|
954
|
+
const styleName = viteId.split('/').pop() || viteId.split('\\').pop();
|
|
955
|
+
console.log(`[WuSandbox] 📦 FALLBACK injected: ${styleName}`);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
console.log(`[WuSandbox] 🎨 FALLBACK: Total ${injectedCount} styles injected for ${appName}`);
|
|
959
|
+
return injectedCount;
|
|
719
960
|
}
|
|
720
961
|
}
|