Lifecycle y ownership
Registro, mount, props vivas, desmontaje, keep-alive y limpieza de recursos por aplicación.
Consulta las versiones, cambios y requisitos en Framework 4.0 y CLI 1.2.
Registro no equivale a montaje
wu.init registra metadatos y permisos. wu.define registra funciones. wu.mount resuelve una app, prepara su contenedor, carga su entry si falta la definición y ejecuta el renderer. El nombre une esos tres pasos.
import { wu } from 'wu-framework';
let stop = () => {};
let abort = null;
wu.define('activity', {
mount(container, { wu: appWu }) {
abort = new AbortController();
const output = document.createElement('output');
const refresh = () => {
output.textContent = String(appWu.store.get('activity.count') ?? 0);
};
container.replaceChildren(output);
stop = appWu.store.on('activity.count', refresh);
refresh();
container.addEventListener('click', () => {
appWu.emit('activity:opened', { source: 'counter' });
}, { signal: abort.signal });
},
update(container, props) {
container.setAttribute('aria-label', props.label ?? 'Actividad');
},
unmount(container) {
stop();
abort?.abort();
container.replaceChildren();
},
});
La app necesita solicitudes y grants para leer activity.count y emitir activity:opened. El ejemplo conserva la facade recibida; el import de wu se utiliza para registrar el lifecycle.
Slots disponibles
| Slot | Firma / uso |
|---|---|
mount |
(container, { appName, wu }); obligatorio |
unmount |
(container, context); libera renderer, listeners y recursos propios |
update |
(container, nextProps); actualización sin desmontar |
hydrate |
(container, { appName, wu, props }); adopta marcado SSR |
deactivate |
(container); se invoca antes de ocultar con keep-alive |
activate |
(container); reactiva una app preservada |
Los slots admiten promesas. Rechazar una promesa en mount permite que el core limpie el intento y consulte la recuperación. Ocultar un error sin renderizar nada hace que WU pueda considerar exitoso el montaje; lanza errores cuando realmente no puedas montar.
Secuencia observable
El montaje ejecuta beforeLoad, el hook de plugin beforeMount, crea el sandbox, ejecuta afterLoad, obtiene o carga la definición, ejecuta beforeMount, espera estilos y llama hydrate o mount. Luego registra el estado montado y ejecuta hooks posteriores.
afterLoad se ejecuta después de crear el sandbox y antes de resolver/cargar el lifecycle. Usa afterMount cuando necesites reaccionar al árbol ya montado.
El core serializa las transiciones sobre un mismo contenedor. Una app no debe borrar un nodo cuya propiedad ya se transfirió a otra. También existe conteo de referencias y desmontaje diferido para absorber ciclos de integración como React StrictMode. Si varios consumidores comparten una app, cada montaje debe tener un desmontaje correspondiente.
Props vivas
const updated = await wu.update('activity', { label: 'Actividad reciente' });
if (!updated) console.info('La app no aplicó esta actualización');
update no fabrica un renderer si la app no implementa ese slot. Los adapters React y Vue conservan props y actualizan su raíz sin remount. Las props iniciales se configuran en el registro del adapter o en SSR; WuLifecycle.mount no declara context.props para el montaje normal.
Ocultar y destruir
await wu.hide('activity');
console.log(wu.isHidden('activity'));
await wu.show('activity');
await wu.unmount('activity', { force: true });
hide conserva DOM, iframe cuando existe, estado, timers y listeners. La aplicación sigue consumiendo recursos; deactivate es el lugar para pausar trabajo propio que no interesa mientras está oculta. show restaura visibilidad y ejecuta activate sin volver a cargar el entry.
unmount resuelve keepAlive en este orden: force obliga a destruir; de lo contrario prevalece la opción de la llamada, luego la config de la app y finalmente false. Desmontar por completo revoca la identidad scoped, listeners y handlers asociados. Una referencia a context.wu conservada después del desmontaje falla con WU_APP_SCOPE_REVOKED.
wu.destroy() limpia el runtime completo. Úsalo cuando el shell deja de existir, no para cambiar una sola sección. wu.app(name, config) entrega un wrapper con mount, unmount, hide, show, remount, reload, verify, start, stop y destroy.
Wrapper: registro diferido y concurrencia
wu.app(name, config) agrupa la identidad, configuración y destino de una aplicación. Crear el wrapper conserva esos datos; el registro efectivo ocurre al montar, a través del core y de su validación de manifest y permisos. Si el core aún no se ha iniciado, el wrapper inicia esa configuración antes de montar.
const widget = wu.app('widget', {
url: '/apps/widget',
container: '#widget-slot',
framework: 'vue',
grants: [],
});
await widget.mount();
console.log(widget.isMounted, widget.info.container);
await widget.hide();
await widget.show();
await widget.unmount({ force: true });
La URL debe servir el manifest de widget. mount(selector) permite elegir otro destino y lo conserva para llamadas posteriores sin argumento. Los métodos de montaje, desmontaje, visibilidad, remount y reload resuelven al mismo wrapper, para poder inspeccionar su estado al terminar.
| Miembro | Uso |
|---|---|
mount(selector?) / start(selector?) |
Registrar si hace falta y montar sobre un selector string |
unmount(options?) / stop() |
Desmontar; stop utiliza las opciones por defecto |
hide() / show() |
Conservar y reactivar una app montada |
remount(selector?) |
Forzar desmontaje y volver a montar |
reload() |
Desmontar, limpiar cachés del loader/manifest disponibles y montar de nuevo |
isMounted / isHidden |
Consultar estado del wrapper y del core |
info |
Nombre, URL, selector, montaje y status |
verify() |
Inspeccionar registro, selector y Shadow DOM del contenedor |
Si otro init está en vuelo, el wrapper lo espera y registra su app después si aún falta. Dos mounts concurrentes sobre el mismo wrapper comparten una promesa de registro; cada montaje sigue participando en el ownership/conteo de referencias del core. Un fallo libera esa promesa para permitir un reintento. Un registro existente del host se conserva, sin sobrescribir sus grants con los de otro wrapper.
reload() no invalida el caché nativo de módulos ESM del navegador ni garantiza descargar una versión diferente del mismo URL. Para actualizar una versión desplegada, publica entries con identidad de build y coordina su carga desde el shell.
verify().container.hasContent inspecciona los hijos del ShadowRoot del slot; un resultado false no demuestra que un renderer con ownership propio o light DOM esté vacío. WuApp.destroy() elimina la app del mapa público, pero no limpia todos los registros de manifest asociados. Para retirar un renderer usa unmount; para reinicializar el shell completo usa wu.destroy() y un nuevo init, en lugar de tratar el destroy del wrapper como una operación general de sustitución de identidad.
Referencia de implementación
Slots: src/index.d.ts; definición: src/core/wu-core.js; montaje: src/core/wu-core.js; actualización: src/core/wu-core.js; teardown: src/core/wu-core.js; keep-alive: src/core/wu-core.js; wrapper: src/core/wu-app.js. Pruebas: tests/unit/keep-alive.test.js, tests/unit/props-channel.test.js, tests/unit/shared-container-navigation.test.js, tests/unit/scoped-events-teardown.test.js.