DOM, CSS y sandbox
Distingue ownership del DOM, aislamiento de estilos y realm JavaScript sin confundirlos con una frontera de seguridad.
Tres decisiones distintas
El comportamiento de una app depende de dónde se ejecuta JavaScript, quién posee el límite DOM y qué estilos recibe. Configurar una de estas dimensiones no configura automáticamente las otras.
| Modo JavaScript | Ejecución | Uso y límites |
|---|---|---|
module |
import() en la ventana principal |
Módulos modernos de confianza; no aísla globals del host |
strict |
Import real dentro de iframe oculto | Realm separado y cleanup; requiere que el módulo pueda cargarse allí |
eval |
Camino de HTML/scripts clásicos dentro de iframe | Compatibilidad con UMD/IIFE; no soporta módulos ESM como strict |
El modo eval ejecuta scripts en el iframe por su camino de compatibilidad HTML; para módulos ESM utiliza module o strict según el realm que necesites.
Strict y su fallback
await wu.init({
sandbox: 'strict',
strictFallback: false,
apps: [{ name: 'reports', url: '/apps/reports' }],
});
await wu.mount('reports', '#reports-slot');
console.table(wu.getSandboxInfo('reports'));
Un fallo de import dentro del iframe produce error por defecto. strictFallback: true autoriza explícitamente una degradación al modo eval; no arregla un bundle ESM incompatible con ese modo. La opción por aplicación prevalece sobre la global.
getSandboxInfo expone requestedMode, actualMode, isolationLevel, mounted, nativeShadow y domOwnership. Compara requestedMode y actualMode al diagnosticar un fallback: la configuración expresa la preferencia y el estado describe el modo que ejecuta esa app.
Quién posee el DOM
domOwnership |
Resultado |
|---|---|
wu |
WU crea el ShadowRoot exterior y entrega una raíz interna al renderer |
app |
El renderer gestiona su propio límite, útil para LitElement |
light |
Montaje sin el ShadowRoot exterior de WU |
El valor explícito gana. En su ausencia, nativeShadow: true selecciona app, false selecciona wu; sin ambos, framework: 'lit' selecciona app y el resto wu.
El nombre app expresa una responsabilidad, no una garantía de que el componente realmente cree Shadow DOM. Si el renderer no crea su propio límite, su contenido permanece en el árbol DOM que recibió.
Distribución de estilos
Configura el manifest de la aplicación:
{
"name": "reports",
"entry": "assets/reports.js",
"styleMode": "own-only"
}
| Valor | Significado |
|---|---|
shared |
El bridge permite distribución de estilos externos en el ShadowRoot |
isolated / none |
No inyecta estilos externos adicionales |
fully-isolated / own-only |
Inyecta los identificados como pertenecientes a esa app |
El bridge observa cambios y atribuye estilos a aplicaciones. Para una hoja creada por código host, existe wu.tagStyleAsApp(element, appName). No presupongas que una regla CSS global del shell atravesará un ShadowRoot. Custom properties heredadas y propiedades CSS heredables pueden seguir participando en la apariencia del contenido.
El sandbox recibe styleMode desde el manifest. Coloca ahí la decisión de estilos; el campo del mismo nombre en la configuración superior del host no sustituye ese valor durante el montaje.
La frontera de confianza real
El propio iframe documenta que es same-origin y redirige creación de nodos al documento del host. Un nodo puede exponer ownerDocument.defaultView, desde donde un script alcanza el host. Ocultar parent o top no cierra esa vía.
Utiliza estos modos para coordinar código de confianza, globals y limpieza. Para ejecutar código no confiable necesitas otra frontera, como un origen aislado y un protocolo restringido; los iframes same-origin del runtime mantienen acceso potencial al host.
Contenedores y layout
Un slot debe ser territorio exclusivo del renderer. En React/Vue, pon el mensaje de loading como hermano del nodo de montaje: si el shell reconcilia sus hijos dentro del mismo nodo, puede borrar el árbol que WU insertó. El test Vue específico del repositorio reproduce ese fallo silencioso.
fullBleed en configuración host decide si el microfrontend ocupa el alto del slot y se hace responsable de su scroll. Si el contenido debe fluir con el documento, conserva el comportamiento por defecto. El alto del slot y su layout siguen siendo responsabilidad del shell.
Referencia de implementación
Modos: src/core/wu-core.js, src/core/wu-core.js, src/core/wu-core.js, src/core/wu-core.js; ownership: src/core/wu-sandbox.js; límite same-origin: src/core/wu-iframe-sandbox.js. Pruebas: tests/unit/sandbox-honesty.test.js, tests/unit/native-shadow-sandbox.test.js, tests/unit/sandbox-container-ownership.test.js, tests/unit/style-own-only.test.js, tests/unit/style-cross-app.test.js, tests/unit/vue-slot-mount-target.test.js.
En strict, parent.postMessage respeta targetOrigin y entrega como event.source la ventana del sandbox. El acceso interno __wuHostPostMessage fue eliminado. Esta corrección de identidad no convierte el iframe same-origin en aislamiento frente a código hostil.