WU / 文档通用微前端
中文

远程应用与能力端口

通过具有授权与撤销机制的 iframe 和 MessagePort 连接其他源上的应用。

本页介绍 WU Framework 4.0.0。升级现有项目之前,请阅读 Framework 4.0 与 CLI 1.2 迁移指南。

配置宿主

import { wu } from 'wu-framework/core';
import 'wu-framework/ports';
await wu.init({ apps: [{
  name: 'widget', url: 'https://widgets.example/app/', sandbox: 'remote',
  manifest: { entry: 'index.html', wu: { permissions: ['events.emit:widget:*'] } },
  grants: ['events.emit:widget:*'],
  iframe: { title: 'Remote widget', timeout: 15000, callTimeout: 10000 },
}] });
await wu.mount('widget', '#widget-slot');
await wu.update('widget', { theme: 'light' });

在宿主创建 #widget-slot,并从配置的源提供应用。WU 创建 iframe,并向 URL 的精确源传递端口。浏览器执行跨源隔离;端口消息通过 widget 门面执行,并受请求及授予权限的约束。

连接远程文档

import { connect } from 'wu-framework/remote';

const remote = await connect({ hostOrigin: 'https://shell.example' });
const off = remote.onProps(props => {
  document.documentElement.dataset.theme = props.theme;
});
await remote.emit('widget:ready', { ready: true });
await remote.resize(document.body.scrollHeight);

window.addEventListener('pagehide', () => {
  off();
  remote.close();
}, { once: true });

远程文档使用自己的渲染器,并应在 hostOrigin 中只接受宿主实际的源。对宿主的调用是异步的:应等待 store.get、store.set、emit 与 RPC。onProps 接收更新,props 保留最新值;resize 请求高度,whenClosed 用于观察关闭。数据必须支持 structured clone。

iframe 默认使用 allow-scripts allow-same-origin allow-forms,可通过 iframe.sandbox 和 iframe.allow 配置。wu.remoteOf(name) 返回其窗口。hide 保留 iframe;unmount 移除 iframe 并撤销端口。连接错误为 WU_REMOTE_TIMEOUT 和 WU_REMOTE_LOAD_FAILED;远程处理器超时返回 WU_PORT_CALL_TIMEOUT。

两个源的响应头

{ "security": { "frameOrigins": ["https://widgets.example"] } }

在 WU CLI 1.0.0 中,security.frameOrigins 将源加入 frame-src,不会加入 script-src 或 connect-src。远程响应必须通过 frame-ancestors 允许宿主,且不能被 X-Frame-Options 阻止。远程构建还需配置渲染器与 wu-framework/remote 入口。

手动创建端口

const capability = await wu.ports.mint('widget', { props: { theme: 'dark' } });
worker.postMessage({ wu: 1, type: 'port', app: 'widget' }, [capability.port]);
await capability.ready;
capability.push({ theme: 'light' });
capability.close('finished');
const active = wu.ports.list();
const revoked = wu.ports.revoke('widget');

宿主需创建 worker,并预先注册带授权的 widget;接收端必须连接远程协议。端口可转移、可关闭。close 撤销当前端口,revoke 关闭该应用的端口。待处理调用返回 WU_PORT_CLOSED。消息通信不会在文档间直接共享 store 对象。

4.0 中的 origin 验证

connect(options) 和 waitForPort(options) 要求 hostOrigin;缺少时产生 WU_REMOTE_HOST_ORIGIN_REQUIRED。"*" 表示明确接受任意 origin。在 iframe 或 popup 中还会验证发送者是否为 parent 或 opener;source 可指定其他窗口。connect(port) 重载接受已收到的 port。

应用 origin 取自其 url。其他 origin 上的 entry 会产生 WU_REMOTE_ORIGIN_MISMATCH。与 shell 同源的远程应用会产生 WU_REMOTE_SAME_ORIGIN,除非设置 iframe.allowSameOrigin: true;该例外将失去跨 origin 隔离。wu.detach() 以 WU_WINDOW_REMOTE_UNSUPPORTED 拒绝远程应用。

host 会在 load 后持续提供 port,直到收到响应,因此远程端可先等待其他工作再连接。通过 port 使用 consume() 时,仅允许已声明 shape 内的方法;没有 shape 时排除 Object.prototype 方法。卸载和 destroy() 会撤销 core 的 ports。

一起完善 WU

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

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