# Lifecycle and ownership

Registration, mount, live props, unmounting, keep-alive, and resource cleanup per application.

See versions, changes and requirements in [Framework 4.0 and CLI 1.2](/docs/guides/releases/).


<span id="registro-no-equivale-a-montaje"></span>

<span class="section-anchor" id="section-1"></span>

## Registration does not mean mounting

`wu.init` registers metadata and permissions. `wu.define` registers functions. `wu.mount` resolves an app, prepares its container, loads its entry if the definition is missing, and runs the renderer. The name connects these three steps.

```js
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();
  },
});
```

The app needs requests and grants to read `activity.count` and emit `activity:opened`. The example keeps the received facade; the `wu` import is used to register the lifecycle.

<span id="slots-disponibles"></span>

<span class="section-anchor" id="section-2"></span>

## Available slots

| Slot | Signature / usage |
| --- | --- |
| `mount` | `(container, { appName, wu })`; required |
| `unmount` | `(container, context)`; releases the renderer, listeners, and owned resources |
| `update` | `(container, nextProps)`; update without unmounting |
| `hydrate` | `(container, { appName, wu, props })`; adopts SSR markup |
| `deactivate` | `(container)`; called before hiding with keep-alive |
| `activate` | `(container)`; reactivates a preserved app |

Slots accept promises. Rejecting a promise in `mount` lets the core clean up the attempt and consult recovery. Hiding an error without rendering anything may cause WU to consider mounting successful; throw errors when you truly cannot mount.

<span id="secuencia-observable"></span>

<span class="section-anchor" id="section-3"></span>

## Observable sequence

Mounting runs `beforeLoad`, the `beforeMount` plugin hook, creates the sandbox, runs `afterLoad`, obtains or loads the definition, runs `beforeMount`, waits for styles, and calls `hydrate` or `mount`. It then records mounted state and runs subsequent hooks.

`afterLoad` runs after creating the sandbox and before resolving/loading the lifecycle. Use `afterMount` when you need to react to the mounted tree.

The core serializes transitions on the same container. An app must not erase a node whose ownership has transferred to another app. Reference counting and deferred unmounting also absorb integration cycles such as React StrictMode. If several consumers share an app, each mount must have a corresponding unmount.

<span id="props-vivas"></span>

<span class="section-anchor" id="section-4"></span>

## Live props

```js
const updated = await wu.update('activity', { label: 'Actividad reciente' });
if (!updated) console.info('La app no aplicó esta actualización');
```

`update` does not create a renderer if the app does not implement that slot. React and Vue adapters retain props and update their root without remounting. Initial props are configured during adapter registration or SSR; `WuLifecycle.mount` does not declare `context.props` for normal mounting.

<span id="ocultar-y-destruir"></span>

<span class="section-anchor" id="section-5"></span>

## Hide and destroy

```js
await wu.hide('activity');
console.log(wu.isHidden('activity'));
await wu.show('activity');
await wu.unmount('activity', { force: true });
```

`hide` preserves DOM, an iframe if present, state, timers, and listeners. The application keeps consuming resources; `deactivate` is the place to pause owned work that is unnecessary while hidden. `show` restores visibility and runs `activate` without reloading the entry.

`unmount` resolves `keepAlive` in this order: `force` requires destruction; otherwise, the call option takes precedence, followed by app configuration, then `false`. Fully unmounting revokes the scoped identity and associated listeners and handlers. A `context.wu` reference retained after unmounting fails with `WU_APP_SCOPE_REVOKED`.

`wu.destroy()` cleans up the entire runtime. Use it when the shell ceases to exist, not to change a single section. `wu.app(name, config)` returns a wrapper with `mount`, `unmount`, `hide`, `show`, `remount`, `reload`, `verify`, `start`, `stop`, and `destroy`.

<span id="wrapper-registro-diferido-y-concurrencia"></span>

<span class="section-anchor" id="section-6"></span>

## Wrapper: deferred registration and concurrency

`wu.app(name, config)` groups an application's identity, configuration, and target. Creating the wrapper retains those values; actual registration occurs on mount, through the core and its manifest and permission validation. If the core has not started yet, the wrapper initializes that configuration before mounting.

```js
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 });
```

The URL must serve the `widget` manifest. `mount(selector)` lets you choose another target and retains it for later calls without an argument. Mount, unmount, visibility, remount, and reload methods resolve to the same wrapper, so you can inspect its state on completion.

| Member | Usage |
| --- | --- |
| `mount(selector?)` / `start(selector?)` | Register if needed and mount on a string selector |
| `unmount(options?)` / `stop()` | Unmount; stop uses default options |
| `hide()` / `show()` | Preserve and reactivate a mounted app |
| `remount(selector?)` | Force unmount and mount again |
| `reload()` | Unmount, clear available loader/manifest caches, and mount again |
| `isMounted` / `isHidden` | Query wrapper and core state |
| `info` | Name, URL, selector, mounted state, and status |
| `verify()` | Inspect registration, selector, and container Shadow DOM |

If another `init` is in flight, the wrapper waits for it and then registers its app if still missing. Two concurrent mounts on **the same wrapper** share a registration promise; each mount still participates in the core's ownership/reference counting. A failure releases that promise to allow a retry. An existing host registration is preserved, without overwriting its grants with another wrapper's.

`reload()` does not invalidate the browser's native ESM module cache or guarantee downloading a different version of the same URL. To update a deployed version, publish entries with build identities and coordinate loading from the shell.

`verify().container.hasContent` inspects the slot's ShadowRoot children; a false result does not prove that a renderer with its own ownership or light DOM is empty. `WuApp.destroy()` removes the app from the public map but does not clear all associated manifest registrations. Use `unmount` to remove a renderer; to reinitialize the entire shell, use `wu.destroy()` followed by a new `init`, instead of treating wrapper destroy as a general identity replacement operation.

<span id="referencia-de-implementación"></span>

<span class="section-anchor" id="section-7"></span>

## Implementation references

Slots: `src/index.d.ts`; definition: `src/core/wu-core.js`; mounting: `src/core/wu-core.js`; updates: `src/core/wu-core.js`; teardown: `src/core/wu-core.js`; keep-alive: `src/core/wu-core.js`; wrapper: `src/core/wu-app.js`. Tests: `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`.