Añadir un shell
El shell es la página que aloja las micro-apps. Es dueño del layout, del
enrutado y de la raíz de confianza. Llama a wu.init() una vez y después a
wu.mount() por cada app que quiere en pantalla.
Un shell puede ser cualquier cosa que ejecute JavaScript en un navegador: un archivo HTML estático, un sitio Astro, una app de Next o una SPA de React. No necesita compartir framework con ninguna de las apps que aloja.
El shell más pequeño
Sección titulada «El shell más pequeño»<!DOCTYPE html><html> <body> <div id="cart"></div> <div id="catalog"></div>
<script type="module"> import { wu } from 'wu-framework';
await wu.init({ apps: [ { name: 'cart', url: 'http://localhost:5173' }, { name: 'catalog', url: 'http://localhost:5174' }, ], });
await wu.mount('cart', '#cart'); await wu.mount('catalog', '#catalog'); </script> </body></html>init() obtiene por adelantado el wu.json de cada app y la registra.
mount() crea el shadow root, carga el bundle de entrada, espera a
wu.define() y ejecuta el mount de la app.
wu.init(config)
Sección titulada «wu.init(config)»| Campo | Tipo | Por defecto | Significado |
|---|---|---|---|
apps |
WuAppConfig[] |
[] |
Apps a registrar |
sandbox |
'module' | 'strict' | 'eval' |
'module' |
Modo de sandbox global |
strictFallback |
boolean |
false |
Permite que strict degrade a eval si falla el import del iframe |
overrides |
object |
— | Configuración de overrides por cookie para QA |
init() es idempotente: llamarlo por segunda vez registra un aviso y
retorna. Eso es lo que lo hace seguro dentro de un efecto de React o de un
layout de Astro que se renderiza en cada página.
Si el manifiesto de alguna app no supera la validación de seguridad, init()
lanza un error. Un manifiesto ausente (404) no lo hace: produce un
manifiesto por defecto. Mira El manifiesto.
Configuración por app
Sección titulada «Configuración por app»await wu.init({ apps: [ { name: 'cart', url: 'https://cart.example.com', sandbox: 'strict', // sobrescribe el modo global strictFallback: false, // override por app keepAlive: true, // ocultar en vez de destruir al desmontar strategy: 'eager', // política de precarga roles: ['admin'], // control RBAC container: '#cart', // informativo; mount() recibe el selector }, ],});| Campo | Tipo | Notas |
|---|---|---|
name |
string |
Debe coincidir con lo que la app pasa a wu.define() |
url |
string |
URL base; wu.json se obtiene de <url>/wu.json |
sandbox |
'module' | 'strict' | 'eval' |
Override por app del modo global |
strictFallback |
boolean |
Override por app; si falta, usa el valor global |
keepAlive |
boolean |
Mira Pestañas keep-alive |
strategy |
'lazy' | 'eager' | 'preload' | 'idle' |
Cuándo se descarga el bundle |
roles |
string[] |
Roles con permiso para montar esta app (RBAC) |
Estrategias de carga
Sección titulada «Estrategias de carga»strategy controla cuándo se descarga el bundle de la app, independientemente
de cuándo se monta.
| Estrategia | Comportamiento |
|---|---|
lazy (por defecto) |
No pasa nada hasta mount() |
eager |
Se precarga durante init() |
preload |
Emite una pista <link rel="modulepreload"> / Speculation Rules |
idle |
Se encola en requestIdleCallback (con respaldo en setTimeout) |
También puedes controlar la precarga a mano:
wu.prefetch(['cart', 'catalog']);wu.prefetchAll();Montar y desmontar
Sección titulada «Montar y desmontar»await wu.mount('cart', '#cart');await wu.unmount('cart');await wu.unmount('cart', { keepAlive: true }); // ocultar, preservar el estadoawait wu.unmount('cart', { force: true }); // destruir ya, sin periodo de graciamount() lleva conteo de referencias con un temporizador de gracia de 60 ms
en el último desmontaje, y eso es lo que hace inofensivos los efectos de doble
invocación de React StrictMode y las reentradas de Suspense. Los detalles están
en Ciclo de vida.
El montaje también se autorrepara: un montaje fallido se reintenta hasta tres veces con backoff cuando el error boundary pide un reintento, y el sandbox se limpia entre intentos para que no quede nada huérfano.
Un shell dirigido por el router
Sección titulada «Un shell dirigido por el router»Montar al navegar, desmontar al salir:
const routes = { '/cart': { app: 'cart', el: '#outlet' }, '/catalog': { app: 'catalog', el: '#outlet' },};
let current = null;
async function navigate(path) { const route = routes[path]; if (!route) return; if (current && current !== route.app) await wu.unmount(current); await wu.mount(route.app, route.el); current = route.app;}
window.addEventListener('popstate', () => navigate(location.pathname));Si quieres pestañas que conserven su estado al ocultarse, usa keepAlive: true
en lugar de destruir — mira Pestañas keep-alive.
De qué se responsabiliza el shell
Sección titulada «De qué se responsabiliza el shell»Wu deliberadamente no asume estas tareas:
- Autenticación. El shell decide quién es el usuario. El
RBAC de Wu solo controla
mount()en el cliente; la barrera de verdad es que tu servidor se niegue a servir el bundle. - Layout y enrutado. Wu monta en los selectores que le des.
- CSS global. En el modo de estilos
sharedpor defecto, las hojas de estilo del shell son las que heredan todas las apps. Mira Aislamiento de CSS. - Confianza. El shell es la raíz de confianza. Nada del lado del cliente puede proteger una página cuyo propio HTML está comprometido — mira el modelo de amenazas.
Verificar lo que has obtenido
Sección titulada «Verificar lo que has obtenido»await wu.mount('cart', '#cart');
const info = wu.getSandboxInfo('cart');// { requestedMode: 'strict', actualMode: 'strict',// isolationLevel: 'iframe', mounted: true }
console.log(wu.inspect()); // instantánea completa de la páginaQue actualMode difiera de requestedMode significa que una app strict
degradó a eval — algo solo posible si activaste strictFallback: true.
Shells con meta-frameworks
Sección titulada «Shells con meta-frameworks»Si tu shell es Astro o Next, usa los componentes incluidos en lugar de escribir a mano las llamadas a init y mount — incluida la variante renderizada en servidor. Mira Astro y Next.js.
Siguiente
Sección titulada «Siguiente»Errores comunes — léelo antes de tu primer despliegue a producción, no después.
