WU / DOCSUNIVERSAL MICROFRONTENDS
EN

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.

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.

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.

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.

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.

Live props

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.

Hide and destroy

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.

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.

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.

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.

BUILD WU WITH US

Found a bug? Have an idea?

Your experience improves WU. Tell us what went wrong or help support its development.