WU / 文档通用微前端
中文

导航与组合

将 shell 的 URL 和导航意图连接到应用的挂载、卸载与状态。

shell 负责导航

shell 决定每条路由对应哪个应用,并通过挂载、卸载、事件和状态组合应用。Astro 可以解析页面;React/Vue router 可以管理应用内部路由。WU core 不包含 wu.router 或 wu.navigate():将 shell 使用的导航机制连接到生命周期即可。

wu.json 中的 metadata.routes 是描述性信息。解析器验证字符串、重复项和限制,但不会安装 History API handlers。Framework 4 拒绝非空的 wu.routes,不应将其用作路由方案。

两个路由层级

层级 示例 负责方
门户页面 /docs/framework/state Astro 文件路由器
shell 动态区域 /workspace/catalog shell 控制器/路由器
应用内部视图 catalog 内的 /products/:id 该应用的路由器

下载 base URL(如 /apps/catalog)属于技术资源,不必与导航路由相同。应分别定义 bundle base、内部 router base 和用户看到的路径。

连接导航意图

此示例实现 shell 的一种约定;shell:navigate 不会激活内置路由器:

const routeTable = new Map([
  ['/workspace/catalog', 'catalog'],
  ['/workspace/reports', 'reports'],
]);

let activeApp = null;
let transition = Promise.resolve();

function showRoute(path) {
  transition = transition.catch(() => {}).then(async () => {
    const nextApp = routeTable.get(path);
    if (!nextApp || nextApp === activeApp) return;
    if (activeApp) await wu.unmount(activeApp, { force: true });
    activeApp = null;
    await wu.mount(nextApp, '#workspace-slot');
    activeApp = nextApp;
  });
  return transition;
}

const stop = wu.on('shell:navigate', ({ data }) => {
  if (!routeTable.has(data?.path)) return;
  history.pushState(null, '', data.path);
  showRoute(data.path).catch(console.error);
});

const onPopState = () => showRoute(location.pathname).catch(console.error);
window.addEventListener('popstate', onPopState);
await showRoute(location.pathname);

// Al retirar el controlador del shell:
// stop();
// window.removeEventListener('popstate', onPopState);

映射表限制可接受的路由和应用。用户在加载结束前多次导航时,队列保留顺序。core 也会协调容器所有权;shell 保持清晰状态,可以避免旧 Promise 更新新路由的导航控件。

Shadow DOM 内的元素

wu.mount(name, selector) 使用 document.querySelector 解析选择器。该选择器不会穿越 ShadowRoots,当前签名接受字符串,不接受 HTMLElement。要让 shell 找到 slot,请将其放在 light DOM 中,或通过组合方式暴露可由选择器访问的节点。

生命周期内应使用收到的 container 操作局部根节点,不要再通过 ID 全局查找。仓库中的 Vue adapter 展示了为什么稳定根节点应与 loading 指示器并列,而不应使用由 shell 管理的指示器容器。

Keep-alive 与路由切换

hide 保留状态和监听器,需要保留应用容器。多个应用切换使用同一个 slot 时,必须明确选择:卸载原所有者,或为每个需要保持活动的应用保留独立容器。keep-alive 与模块缓存管理的是不同资源。

如果 Astro 通过客户端导航替换页面,bootstrap 必须配合该生命周期:释放上一页的监听器和 mounts,并连接新 slots。脚本导入去重不代表未来出现的所有节点都会自动挂载。

UI 角色

wu.setPrincipal({ id: 'u1', roles: ['catalog-reader'] }) 为 wu.can('catalog') 提供身份信息。挂载会检查 manifest 要求的角色,可能以 WU_ACCESS_DENIED 拒绝。这有助于保持导航与视图一致;数据 API 仍应在服务器上授权每个请求。

实现参考

描述性路由验证:src/core/wu-manifest.js;访问控制:src/core/wu-core.js 和 src/core/wu-core.js;选择器:src/core/wu-core.js;容器转换:src/core/wu-core.js;MCP 使用的约定:src/core/wu-mcp-bridge.js。测试:tests/unit/shared-container-navigation.test.js、tests/unit/sandbox-container-ownership.test.js、tests/unit/rbac.test.js。

一起完善 WU

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

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