wu-framework 1.1.1 → 1.1.3
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 +392 -988
- package/package.json +1 -1
- package/src/core/wu-core.js +25 -0
- package/src/core/wu-manifest.js +31 -2
- package/src/core/wu-style-bridge.js +323 -9
package/package.json
CHANGED
package/src/core/wu-core.js
CHANGED
|
@@ -587,6 +587,23 @@ export class WuCore {
|
|
|
587
587
|
// 🏊 Acquire sandbox from pool (if configured)
|
|
588
588
|
const poolSandbox = this.sandboxPool.acquire(appName);
|
|
589
589
|
|
|
590
|
+
// 🎨 Configure style mode from manifest before creating sandbox
|
|
591
|
+
const manifest = app.manifest;
|
|
592
|
+
console.log(`[Wu] 🔍 DEBUG: Manifest for ${appName}:`, JSON.stringify(manifest, null, 2));
|
|
593
|
+
|
|
594
|
+
// Default to 'isolated' if no styleMode specified
|
|
595
|
+
const styleMode = manifest?.styleMode || 'isolated';
|
|
596
|
+
if (this.sandbox.styleBridge) {
|
|
597
|
+
// Pass app URL so StyleBridge can identify MFE's own styles
|
|
598
|
+
this.sandbox.styleBridge.setAppStyleMode(appName, styleMode, app.url);
|
|
599
|
+
console.log(`[Wu] 🎨 Style mode for ${appName}: ${styleMode}`);
|
|
600
|
+
|
|
601
|
+
// 📁 If folder is specified in manifest, register it for style detection
|
|
602
|
+
// This is needed when folder name differs from app name (e.g., folder="container", name="content")
|
|
603
|
+
const folderName = manifest?.folder || appName;
|
|
604
|
+
this.sandbox.styleBridge.setAppFolder(appName, `/${folderName}/`);
|
|
605
|
+
}
|
|
606
|
+
|
|
590
607
|
// 🛡️ Quantum sandbox creation
|
|
591
608
|
const sandbox = this.sandbox.create(appName, container);
|
|
592
609
|
|
|
@@ -603,6 +620,14 @@ export class WuCore {
|
|
|
603
620
|
if (!lifecycle) {
|
|
604
621
|
throw new Error(`App ${appName} did not register with wu.define()`);
|
|
605
622
|
}
|
|
623
|
+
|
|
624
|
+
// 🎨 RE-INJECT STYLES: After remote module loads, Vite may have injected new styles
|
|
625
|
+
// We need to re-scan and inject any new styles into the Shadow DOM
|
|
626
|
+
if (sandbox.shadowRoot && this.sandbox.styleBridge) {
|
|
627
|
+
console.log(`[Wu] 🎨 Re-injecting styles after module load for ${appName}...`);
|
|
628
|
+
// Pass app URL so StyleBridge can identify MFE's own styles
|
|
629
|
+
await this.sandbox.styleBridge.injectStylesIntoShadow(sandbox.shadowRoot, appName, app.url);
|
|
630
|
+
}
|
|
606
631
|
}
|
|
607
632
|
|
|
608
633
|
// 🪝 Execute beforeMount hooks
|
package/src/core/wu-manifest.js
CHANGED
|
@@ -43,14 +43,19 @@ export class WuManifest {
|
|
|
43
43
|
defineSchema() {
|
|
44
44
|
this.schemas.set('wu.json', {
|
|
45
45
|
required: ['name', 'entry'],
|
|
46
|
-
optional: ['wu'],
|
|
46
|
+
optional: ['wu', 'styleMode'],
|
|
47
47
|
wu: {
|
|
48
48
|
optional: ['exports', 'imports', 'routes', 'permissions'],
|
|
49
49
|
exports: 'object',
|
|
50
50
|
imports: 'array',
|
|
51
51
|
routes: 'array',
|
|
52
52
|
permissions: 'array'
|
|
53
|
-
}
|
|
53
|
+
},
|
|
54
|
+
// 🎨 styleMode: 'isolated' | 'shared' | 'auto'
|
|
55
|
+
// - isolated: No comparte estilos del padre (default, máximo aislamiento)
|
|
56
|
+
// - shared: Comparte todos los estilos del padre
|
|
57
|
+
// - auto: Solo comparte estilos de librerías específicas (element-plus, etc.)
|
|
58
|
+
styleMode: 'string'
|
|
54
59
|
});
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -312,7 +317,11 @@ export class WuManifest {
|
|
|
312
317
|
normalize(manifest) {
|
|
313
318
|
const normalized = {
|
|
314
319
|
name: manifest.name.trim(),
|
|
320
|
+
// 📁 folder: carpeta física del MFE (si difiere del name)
|
|
321
|
+
folder: manifest.folder?.trim() || manifest.name.trim(),
|
|
315
322
|
entry: this.normalizeEntry(manifest.entry),
|
|
323
|
+
// 🎨 styleMode: 'isolated' (default) | 'shared' | 'auto'
|
|
324
|
+
styleMode: this.normalizeStyleMode(manifest.styleMode),
|
|
316
325
|
wu: {
|
|
317
326
|
exports: manifest.wu?.exports || {},
|
|
318
327
|
imports: manifest.wu?.imports || [],
|
|
@@ -342,6 +351,26 @@ export class WuManifest {
|
|
|
342
351
|
return normalized;
|
|
343
352
|
}
|
|
344
353
|
|
|
354
|
+
/**
|
|
355
|
+
* 🎨 Normalizar styleMode
|
|
356
|
+
* @param {string} styleMode - Modo de estilos
|
|
357
|
+
* @returns {'isolated' | 'fully-isolated' | 'shared' | 'auto'} styleMode normalizado
|
|
358
|
+
*
|
|
359
|
+
* Modos disponibles:
|
|
360
|
+
* - 'isolated': MFE solo tiene sus propios estilos (CSS variables SÍ se heredan)
|
|
361
|
+
* - 'fully-isolated': Aislamiento TOTAL - resetea CSS variables del padre (ÚNICO en wu-framework!)
|
|
362
|
+
* - 'shared': Comparte todos los estilos del padre
|
|
363
|
+
* - 'auto': Comparte solo librerías específicas (element-plus, etc.)
|
|
364
|
+
*/
|
|
365
|
+
normalizeStyleMode(styleMode) {
|
|
366
|
+
const validModes = ['isolated', 'fully-isolated', 'shared', 'auto'];
|
|
367
|
+
if (styleMode && validModes.includes(styleMode)) {
|
|
368
|
+
return styleMode;
|
|
369
|
+
}
|
|
370
|
+
// Default: isolated (máximo aislamiento sin romper CSS variables)
|
|
371
|
+
return 'isolated';
|
|
372
|
+
}
|
|
373
|
+
|
|
345
374
|
/**
|
|
346
375
|
* Normalizar entry path
|
|
347
376
|
* @param {string} entry - Entry path
|
|
@@ -3,14 +3,26 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Comparte automáticamente estilos de node_modules entre padre e hijos Shadow DOM
|
|
5
5
|
* Soluciona el problema de aislamiento CSS en microfrontends
|
|
6
|
+
*
|
|
7
|
+
* 🚀 STYLE MODES:
|
|
8
|
+
* - 'isolated': MFE solo tiene sus propios estilos (CSS variables SÍ se heredan)
|
|
9
|
+
* - 'fully-isolated': Aislamiento TOTAL - resetea CSS variables del padre
|
|
10
|
+
* - 'shared': Comparte todos los estilos del padre
|
|
11
|
+
* - 'auto': Comparte solo librerías específicas (element-plus, etc.)
|
|
6
12
|
*/
|
|
7
13
|
|
|
8
14
|
export class WuStyleBridge {
|
|
9
15
|
constructor() {
|
|
10
16
|
this.sharedStyles = new Map();
|
|
11
17
|
this.styleObserver = null;
|
|
18
|
+
this.appStyleModes = new Map(); // Per-app style isolation mode
|
|
12
19
|
this.config = {
|
|
13
|
-
//
|
|
20
|
+
// 🛡️ DEFAULT MODE: 'isolated' = cada MFE tiene sus propios estilos
|
|
21
|
+
// 'fully-isolated' = aislamiento total incluyendo CSS variables
|
|
22
|
+
// 'shared' = compartir estilos del padre
|
|
23
|
+
// 'auto' = compartir solo librerías específicas
|
|
24
|
+
defaultMode: 'isolated',
|
|
25
|
+
// Librerías que se deben compartir automáticamente (solo en modo 'auto')
|
|
14
26
|
autoShareLibraries: [
|
|
15
27
|
'element-plus',
|
|
16
28
|
'vue-flow',
|
|
@@ -20,20 +32,51 @@ export class WuStyleBridge {
|
|
|
20
32
|
'normalize.css',
|
|
21
33
|
'reset.css'
|
|
22
34
|
],
|
|
23
|
-
// Patrones de URLs a compartir
|
|
35
|
+
// Patrones de URLs a compartir (solo en modo 'auto' o 'shared')
|
|
24
36
|
sharePatterns: [
|
|
25
37
|
/\/node_modules\//,
|
|
26
38
|
/\/@vite\/client/,
|
|
27
39
|
/\/dist\/index\.css$/,
|
|
28
40
|
/\/dist\/style\.css$/
|
|
29
41
|
],
|
|
30
|
-
// Modo de compartición
|
|
31
|
-
mode: 'auto', // 'auto' | 'manual' | 'all'
|
|
32
42
|
// Caché de estilos
|
|
33
43
|
cacheEnabled: true
|
|
34
44
|
};
|
|
35
45
|
|
|
36
|
-
console.log('[WuStyleBridge] 🎨 Style sharing system initialized');
|
|
46
|
+
console.log('[WuStyleBridge] 🎨 Style sharing system initialized (default: isolated)');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 🛡️ SET APP STYLE MODE: Configura el modo de estilos para una app específica
|
|
51
|
+
* @param {string} appName - Nombre de la app
|
|
52
|
+
* @param {'isolated' | 'shared' | 'auto'} mode - Modo de estilos
|
|
53
|
+
* @param {string} appUrl - URL base del MFE (opcional)
|
|
54
|
+
*/
|
|
55
|
+
setAppStyleMode(appName, mode, appUrl = null) {
|
|
56
|
+
this.appStyleModes.set(appName, mode);
|
|
57
|
+
if (appUrl) {
|
|
58
|
+
this.appUrls = this.appUrls || new Map();
|
|
59
|
+
this.appUrls.set(appName, appUrl);
|
|
60
|
+
}
|
|
61
|
+
console.log(`[WuStyleBridge] 🎨 Style mode for ${appName}: ${mode}${appUrl ? ` (url: ${appUrl})` : ''}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 🔗 GET APP URL: Obtiene la URL de una app
|
|
66
|
+
* @param {string} appName - Nombre de la app
|
|
67
|
+
* @returns {string|null}
|
|
68
|
+
*/
|
|
69
|
+
getAppUrl(appName) {
|
|
70
|
+
return this.appUrls?.get(appName) || null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 🔍 GET APP STYLE MODE: Obtiene el modo de estilos de una app
|
|
75
|
+
* @param {string} appName - Nombre de la app
|
|
76
|
+
* @returns {'isolated' | 'shared' | 'auto'}
|
|
77
|
+
*/
|
|
78
|
+
getAppStyleMode(appName) {
|
|
79
|
+
return this.appStyleModes.get(appName) || this.config.defaultMode;
|
|
37
80
|
}
|
|
38
81
|
|
|
39
82
|
/**
|
|
@@ -137,26 +180,61 @@ export class WuStyleBridge {
|
|
|
137
180
|
}
|
|
138
181
|
|
|
139
182
|
/**
|
|
140
|
-
* 🌉 INYECTAR ESTILOS EN SHADOW DOM: Clona estilos al Shadow DOM
|
|
183
|
+
* 🌉 INYECTAR ESTILOS EN SHADOW DOM: Clona estilos al Shadow DOM según el modo
|
|
141
184
|
* @param {ShadowRoot} shadowRoot - Shadow DOM donde inyectar
|
|
142
185
|
* @param {string} appName - Nombre de la app
|
|
186
|
+
* @param {string} appUrl - URL base del MFE (opcional, para detectar sus propios estilos)
|
|
143
187
|
* @returns {Promise<number>}
|
|
144
188
|
*/
|
|
145
|
-
async injectStylesIntoShadow(shadowRoot, appName) {
|
|
189
|
+
async injectStylesIntoShadow(shadowRoot, appName, appUrl = null) {
|
|
146
190
|
if (!shadowRoot) {
|
|
147
191
|
console.warn('[WuStyleBridge] ⚠️ No shadow root provided');
|
|
148
192
|
return 0;
|
|
149
193
|
}
|
|
150
194
|
|
|
151
|
-
|
|
195
|
+
// 🛡️ CHECK STYLE MODE
|
|
196
|
+
const styleMode = this.getAppStyleMode(appName);
|
|
197
|
+
// Use stored URL if not provided
|
|
198
|
+
const resolvedAppUrl = appUrl || this.getAppUrl(appName);
|
|
199
|
+
console.log(`[WuStyleBridge] 🌉 Injecting styles into ${appName} (mode: ${styleMode}, url: ${resolvedAppUrl || 'none'})...`);
|
|
200
|
+
|
|
201
|
+
// 🔒 FULLY-ISOLATED MODE: Inject CSS variables reset FIRST
|
|
202
|
+
if (styleMode === 'fully-isolated') {
|
|
203
|
+
this.injectCSSVariablesReset(shadowRoot, appName);
|
|
204
|
+
}
|
|
152
205
|
|
|
153
206
|
// Detectar estilos del documento
|
|
154
207
|
const styles = this.detectDocumentStyles();
|
|
155
208
|
let injectedCount = 0;
|
|
156
209
|
|
|
157
|
-
// Inyectar cada estilo
|
|
210
|
+
// Inyectar cada estilo según el modo
|
|
158
211
|
for (const style of styles) {
|
|
159
212
|
try {
|
|
213
|
+
const styleSource = style.href || style.viteId || '';
|
|
214
|
+
|
|
215
|
+
// 🎯 DETECTAR SI EL ESTILO PERTENECE AL MFE
|
|
216
|
+
const isOwnStyle = this.isStyleFromApp(styleSource, appName, resolvedAppUrl);
|
|
217
|
+
|
|
218
|
+
// 🛡️ En modo 'isolated' o 'fully-isolated': SOLO inyectar estilos propios del MFE
|
|
219
|
+
if (styleMode === 'isolated' || styleMode === 'fully-isolated') {
|
|
220
|
+
if (!isOwnStyle) {
|
|
221
|
+
const shortSource = styleSource.split(/[/\\]/).slice(-2).join('/');
|
|
222
|
+
console.log(`[WuStyleBridge] 🚫 ${appName} skipping foreign style: ${shortSource}`);
|
|
223
|
+
continue; // Skip parent/shell styles
|
|
224
|
+
}
|
|
225
|
+
console.log(`[WuStyleBridge] 🎨 ${appName} own style: ${styleSource.split(/[/\\]/).slice(-2).join('/')}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 🎯 En modo 'auto': compartir librerías + estilos propios
|
|
229
|
+
if (styleMode === 'auto') {
|
|
230
|
+
const shouldShare = this.shouldShareStyle(styleSource);
|
|
231
|
+
if (!shouldShare && !isOwnStyle) {
|
|
232
|
+
continue; // Skip this style
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 'shared' mode: inject everything
|
|
237
|
+
|
|
160
238
|
switch (style.type) {
|
|
161
239
|
case 'link':
|
|
162
240
|
await this.injectLinkStyle(shadowRoot, style);
|
|
@@ -182,6 +260,242 @@ export class WuStyleBridge {
|
|
|
182
260
|
return injectedCount;
|
|
183
261
|
}
|
|
184
262
|
|
|
263
|
+
/**
|
|
264
|
+
* 🔒 INJECT CSS VARIABLES RESET: Resetea las CSS variables heredadas del padre
|
|
265
|
+
* Este método detecta todas las CSS variables definidas en el documento padre
|
|
266
|
+
* y las resetea a 'initial' dentro del Shadow DOM para lograr aislamiento total.
|
|
267
|
+
*
|
|
268
|
+
* @param {ShadowRoot} shadowRoot - Shadow DOM donde inyectar el reset
|
|
269
|
+
* @param {string} appName - Nombre de la app para logging
|
|
270
|
+
*/
|
|
271
|
+
injectCSSVariablesReset(shadowRoot, appName) {
|
|
272
|
+
// Verificar si ya existe el reset
|
|
273
|
+
const existingReset = shadowRoot.querySelector('style[data-wu-css-reset="true"]');
|
|
274
|
+
if (existingReset) {
|
|
275
|
+
console.log(`[WuStyleBridge] ⏭️ CSS variables reset already exists for ${appName}`);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// 🔍 Detectar todas las CSS variables del documento padre
|
|
280
|
+
const parentVariables = this.detectParentCSSVariables();
|
|
281
|
+
|
|
282
|
+
if (parentVariables.length === 0) {
|
|
283
|
+
console.log(`[WuStyleBridge] 🔒 No parent CSS variables to reset for ${appName}`);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 🎨 Generar CSS reset
|
|
288
|
+
const resetCSS = this.generateCSSVariablesReset(parentVariables);
|
|
289
|
+
|
|
290
|
+
// Crear style tag con el reset
|
|
291
|
+
const resetStyle = document.createElement('style');
|
|
292
|
+
resetStyle.setAttribute('data-wu-css-reset', 'true');
|
|
293
|
+
resetStyle.setAttribute('data-wu-app', appName);
|
|
294
|
+
resetStyle.textContent = resetCSS;
|
|
295
|
+
|
|
296
|
+
// Insertar al PRINCIPIO del shadow root (antes de otros estilos)
|
|
297
|
+
shadowRoot.insertBefore(resetStyle, shadowRoot.firstChild);
|
|
298
|
+
|
|
299
|
+
console.log(`[WuStyleBridge] 🔒 CSS variables reset injected for ${appName} (${parentVariables.length} variables blocked)`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* 🔍 DETECT PARENT CSS VARIABLES: Detecta todas las CSS variables del documento padre
|
|
304
|
+
* @returns {Array<{name: string, value: string}>} Lista de variables detectadas
|
|
305
|
+
*/
|
|
306
|
+
detectParentCSSVariables() {
|
|
307
|
+
const variables = [];
|
|
308
|
+
const seen = new Set();
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
// 1. Buscar en :root y html
|
|
312
|
+
const rootStyles = getComputedStyle(document.documentElement);
|
|
313
|
+
|
|
314
|
+
// 2. Buscar en todos los stylesheets del documento
|
|
315
|
+
for (const sheet of document.styleSheets) {
|
|
316
|
+
try {
|
|
317
|
+
// Algunos stylesheets (cross-origin) no permiten acceso
|
|
318
|
+
const rules = sheet.cssRules || sheet.rules;
|
|
319
|
+
if (!rules) continue;
|
|
320
|
+
|
|
321
|
+
for (const rule of rules) {
|
|
322
|
+
// Solo procesar reglas de estilo
|
|
323
|
+
if (rule.type !== CSSRule.STYLE_RULE) continue;
|
|
324
|
+
|
|
325
|
+
// Buscar reglas que definen variables (:root, html, body, *)
|
|
326
|
+
const selector = rule.selectorText?.toLowerCase() || '';
|
|
327
|
+
if (selector === ':root' || selector === 'html' || selector === 'body' || selector === '*') {
|
|
328
|
+
const style = rule.style;
|
|
329
|
+
for (let i = 0; i < style.length; i++) {
|
|
330
|
+
const prop = style[i];
|
|
331
|
+
// Las CSS variables empiezan con --
|
|
332
|
+
if (prop.startsWith('--') && !seen.has(prop)) {
|
|
333
|
+
seen.add(prop);
|
|
334
|
+
variables.push({
|
|
335
|
+
name: prop,
|
|
336
|
+
value: style.getPropertyValue(prop).trim()
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
} catch (e) {
|
|
343
|
+
// Ignorar errores de CORS en stylesheets externos
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// 3. También detectar variables inline en el html element
|
|
348
|
+
const htmlStyle = document.documentElement.getAttribute('style') || '';
|
|
349
|
+
const inlineVarMatches = htmlStyle.matchAll(/--([\w-]+)\s*:\s*([^;]+)/g);
|
|
350
|
+
for (const match of inlineVarMatches) {
|
|
351
|
+
const name = `--${match[1]}`;
|
|
352
|
+
if (!seen.has(name)) {
|
|
353
|
+
seen.add(name);
|
|
354
|
+
variables.push({
|
|
355
|
+
name,
|
|
356
|
+
value: match[2].trim()
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
} catch (error) {
|
|
362
|
+
console.warn('[WuStyleBridge] ⚠️ Error detecting CSS variables:', error);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return variables;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* 🎨 GENERATE CSS VARIABLES RESET: Genera el CSS que resetea las variables
|
|
370
|
+
* @param {Array<{name: string, value: string}>} variables - Variables a resetear
|
|
371
|
+
* @returns {string} CSS con el reset
|
|
372
|
+
*/
|
|
373
|
+
generateCSSVariablesReset(variables) {
|
|
374
|
+
// 🔒 TÉCNICA: Redefinir cada variable como "unset" dentro del :host
|
|
375
|
+
// Esto rompe la cadena de herencia de CSS custom properties
|
|
376
|
+
//
|
|
377
|
+
// Problema: CSS variables se heredan a través de Shadow DOM por spec
|
|
378
|
+
// Solución: Redefinirlas explícitamente para "sobrescribir" el valor heredado
|
|
379
|
+
//
|
|
380
|
+
// Usamos valores por defecto del navegador para colores comunes
|
|
381
|
+
// y cadena vacía para otros
|
|
382
|
+
|
|
383
|
+
const resetRules = variables.map(v => {
|
|
384
|
+
const name = v.name;
|
|
385
|
+
// Detectar tipo de variable por su nombre y asignar valor neutro
|
|
386
|
+
if (name.includes('color') || name.includes('bg')) {
|
|
387
|
+
return ` ${name}: transparent;`;
|
|
388
|
+
} else if (name.includes('size') || name.includes('width') || name.includes('height')) {
|
|
389
|
+
return ` ${name}: auto;`;
|
|
390
|
+
} else if (name.includes('font')) {
|
|
391
|
+
return ` ${name}: inherit;`;
|
|
392
|
+
} else {
|
|
393
|
+
// Para otras variables, usar valor vacío que las invalida
|
|
394
|
+
return ` ${name}: initial;`;
|
|
395
|
+
}
|
|
396
|
+
}).join('\n');
|
|
397
|
+
|
|
398
|
+
return `
|
|
399
|
+
/* 🔒 WU-FRAMEWORK: CSS Variables Reset (fully-isolated mode)
|
|
400
|
+
* Este estilo BLOQUEA las CSS variables heredadas del padre
|
|
401
|
+
* para lograr un aislamiento visual completo.
|
|
402
|
+
* Variables bloqueadas: ${variables.length}
|
|
403
|
+
*
|
|
404
|
+
* El MFE debe definir sus propias variables CSS si las necesita.
|
|
405
|
+
* Las variables del padre/shell NO afectarán este componente.
|
|
406
|
+
*/
|
|
407
|
+
|
|
408
|
+
:host {
|
|
409
|
+
/* 🛡️ Bloquear herencia de propiedades CSS del padre */
|
|
410
|
+
all: initial;
|
|
411
|
+
display: block;
|
|
412
|
+
|
|
413
|
+
/* 🔒 Redefinir variables del padre como valores neutros */
|
|
414
|
+
${resetRules}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* Restaurar herencia normal DENTRO del shadow DOM */
|
|
418
|
+
:host * {
|
|
419
|
+
all: revert;
|
|
420
|
+
}
|
|
421
|
+
`.trim();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* 🔗 SET APP FOLDER: Asocia una carpeta del sistema de archivos con un MFE
|
|
426
|
+
* @param {string} appName - Nombre de la app
|
|
427
|
+
* @param {string} folderPath - Ruta de la carpeta (extraída de data-vite-dev-id)
|
|
428
|
+
*/
|
|
429
|
+
setAppFolder(appName, folderPath) {
|
|
430
|
+
this.appFolders = this.appFolders || new Map();
|
|
431
|
+
this.appFolders.set(appName, folderPath.toLowerCase());
|
|
432
|
+
console.log(`[WuStyleBridge] 📁 Folder for ${appName}: ${folderPath}`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* 🔍 DETECTAR SI UN ESTILO PERTENECE A UN MFE
|
|
437
|
+
* @param {string} styleSource - URL o viteId del estilo
|
|
438
|
+
* @param {string} appName - Nombre de la app
|
|
439
|
+
* @param {string} appUrl - URL base del MFE
|
|
440
|
+
* @returns {boolean}
|
|
441
|
+
*/
|
|
442
|
+
isStyleFromApp(styleSource, appName, appUrl) {
|
|
443
|
+
if (!styleSource) return false;
|
|
444
|
+
|
|
445
|
+
const source = styleSource.toLowerCase();
|
|
446
|
+
|
|
447
|
+
// 🎯 PRIORITY 1: Verificar puerto del MFE en localhost URL
|
|
448
|
+
// Ej: "http://localhost:3001/src/style.css" pertenece a MFE en puerto 3001
|
|
449
|
+
if (appUrl) {
|
|
450
|
+
try {
|
|
451
|
+
const appPort = new URL(appUrl).port;
|
|
452
|
+
if (appPort) {
|
|
453
|
+
// Si el estilo viene de localhost con el puerto del MFE
|
|
454
|
+
if (source.includes(`localhost:${appPort}`) ||
|
|
455
|
+
source.includes(`127.0.0.1:${appPort}`)) {
|
|
456
|
+
console.log(`[WuStyleBridge] ✅ Port match: ${appPort} for ${appName}`);
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
// Si el estilo viene de localhost pero con OTRO puerto, NO es de este MFE
|
|
460
|
+
const portMatch = source.match(/localhost:(\d+)|127\.0\.0\.1:(\d+)/);
|
|
461
|
+
if (portMatch) {
|
|
462
|
+
const stylePort = portMatch[1] || portMatch[2];
|
|
463
|
+
if (stylePort && stylePort !== appPort) {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
} catch (e) {
|
|
469
|
+
// Ignore URL parse errors
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// 🎯 PRIORITY 2: Usar la carpeta registrada del MFE
|
|
474
|
+
// Cuando el MFE carga, detectamos su carpeta y la guardamos
|
|
475
|
+
const appFolder = this.appFolders?.get(appName);
|
|
476
|
+
if (appFolder && source.includes(appFolder)) {
|
|
477
|
+
console.log(`[WuStyleBridge] ✅ Folder match for ${appName}`);
|
|
478
|
+
return true;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// 🎯 PRIORITY 3: Para file paths de Vite (data-vite-dev-id)
|
|
482
|
+
// Verificar si el path contiene la carpeta registrada del MFE
|
|
483
|
+
// La carpeta ya fue registrada desde wu-core.js con el valor del manifest
|
|
484
|
+
// Solo comparar, NO auto-detectar ni sobrescribir
|
|
485
|
+
if (appFolder) {
|
|
486
|
+
// El path debe contener la carpeta del MFE (e.g., /container/ o /header/)
|
|
487
|
+
// Normalizar la búsqueda para Windows y Unix paths
|
|
488
|
+
const folderPattern = appFolder.replace(/\//g, '[/\\\\]');
|
|
489
|
+
const folderRegex = new RegExp(folderPattern, 'i');
|
|
490
|
+
if (folderRegex.test(source)) {
|
|
491
|
+
console.log(`[WuStyleBridge] ✅ Folder regex match for ${appName}: ${appFolder}`);
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
|
|
185
499
|
/**
|
|
186
500
|
* 🔗 INYECTAR LINK STYLE: Clona <link> tag al Shadow DOM
|
|
187
501
|
* @param {ShadowRoot} shadowRoot
|