WU / 文档通用微前端
中文

生命周期与所有权

应用的注册、mount、动态 props、卸载、keep-alive 与资源清理。

版本、变更与要求见 Framework 3.2 与 CLI 1.0。

注册不等于挂载

wu.init 注册元数据和权限。wu.define 注册函数。wu.mount 解析应用、准备容器,在缺少定义时加载 entry,然后执行 renderer。名称将这三个步骤关联起来。

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

应用需要相应请求和 grants 才能读取 activity.count 并发射 activity:opened。示例保留收到的 facade;导入的 wu 用于注册生命周期。

可用 slots

Slot 签名 / 用途
mount (container, { appName, wu });必需
unmount (container, context);释放 renderer、监听器和自有资源
update (container, nextProps);无需卸载即可更新
hydrate (container, { appName, wu, props });接管 SSR 标记
deactivate (container);通过 keep-alive 隐藏前调用
activate (container);重新激活保留的应用

slots 支持 Promise。mount 中的 Promise 拒绝后,core 可以清理本次尝试并调用恢复机制。吞掉错误却不渲染任何内容,可能让 WU 将挂载视为成功;确实无法挂载时应抛出错误。

可观察的执行顺序

挂载依次执行 beforeLoad、插件 beforeMount hook、创建 sandbox、执行 afterLoad、获取或加载定义、执行 beforeMount、等待样式,然后调用 hydrate 或 mount。随后记录已挂载状态并执行后续 hooks。

afterLoad 在创建 sandbox 后、解析或加载生命周期前执行。需要对已挂载的树作出响应时,使用 afterMount。

core 将同一容器上的状态转换串行化。应用不应删除所有权已转移给其他应用的节点。系统还提供引用计数和延迟卸载,以吸收 React StrictMode 等集成周期。如果多个使用方共享一个应用,每次挂载都应有对应的卸载。

动态 props

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

如果应用未实现 update slot,它不会凭空创建 renderer。React 和 Vue adapters 保留 props,并在不重新挂载的情况下更新根节点。初始 props 在 adapter 注册或 SSR 中配置;常规挂载的 WuLifecycle.mount 未声明 context.props。

隐藏与销毁

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

hide 保留 DOM、已有 iframe、状态、timers 和监听器。应用仍会占用资源;可在 deactivate 中暂停隐藏期间不需要的自有工作。show 恢复可见性并执行 activate,不会重新加载 entry。

unmount 按以下顺序决定 keepAlive:force 强制销毁;否则先采用本次调用选项,其次是应用配置,最后为 false。完整卸载会撤销 scoped 身份及关联的监听器和 handlers。卸载后保留的 context.wu 引用会以 WU_APP_SCOPE_REVOKED 失败。

wu.destroy() 清理整个运行时。应在 shell 结束时使用,而不是只切换一个区域。wu.app(name, config) 返回含 mount、unmount、hide、show、remount、reload、verify、start、stop 和 destroy 的 wrapper。

Wrapper:延迟注册与并发

wu.app(name, config) 将应用身份、配置和目标组合在一起。创建 wrapper 会保存这些数据;实际注册发生在挂载时,由 core 验证 manifest 和权限。如果 core 尚未启动,wrapper 会先用该配置初始化,再挂载。

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

URL 必须提供 widget 的 manifest。mount(selector) 可选择其他目标,并保存它,供后续无参数调用使用。挂载、卸载、可见性、remount 和 reload 方法都解析为同一个 wrapper,方便结束后检查状态。

成员 用途
mount(selector?) / start(selector?) 必要时注册,并挂载到字符串选择器指定的位置
unmount(options?) / stop() 卸载;stop 使用默认选项
hide() / show() 保留并重新激活已挂载应用
remount(selector?) 强制卸载后重新挂载
reload() 卸载,清除可用的 loader/manifest 缓存,然后重新挂载
isMounted / isHidden 查询 wrapper 和 core 状态
info 名称、URL、选择器、挂载情况和 status
verify() 检查注册、选择器和容器 Shadow DOM

如果另一个 init 正在进行,wrapper 会等待它完成,之后在应用仍未注册时注册。同一个 wrapper 上的两个并发 mounts 共享注册 Promise;每次挂载仍参与 core 的所有权与引用计数。失败会释放该 Promise,以便重试。保留宿主已有的注册,不会用另一个 wrapper 的 grants 覆盖它。

reload() 不会使浏览器原生 ESM 模块缓存失效,也不保证同一 URL 会下载不同版本。更新已部署版本时,应发布带构建身份的 entries,并由 shell 协调加载。

verify().container.hasContent 检查 slot 的 ShadowRoot 子节点;false 不能证明拥有自身 DOM 所有权或使用 light DOM 的 renderer 为空。WuApp.destroy() 从公开映射中删除应用,但不会清理所有关联的 manifest 注册。移除 renderer 使用 unmount;重新初始化整个 shell 使用 wu.destroy() 后再次 init,不要将 wrapper 的 destroy 当作通用的身份替换操作。

实现参考

Slots:src/index.d.ts;定义:src/core/wu-core.js;挂载:src/core/wu-core.js;更新:src/core/wu-core.js;拆卸:src/core/wu-core.js;keep-alive:src/core/wu-core.js;wrapper:src/core/wu-app.js。测试: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。

一起完善 WU

发现了问题?有新的想法?

你的使用体验能让 WU 变得更好。告诉我们遇到的问题,或支持项目的持续开发。