解析与交付
部署解析、策略上下文、缓存、预加载、不可变发布、回滚,以及 transport 所有权。
策略与加载必须分离
逻辑引用不应随着 CDN 搬迁、版本提升、tenant override 或 bundler 更换而变化:
const ref = {
name: 'checkout',
expose: './application',
range: '^2.4.0',
channel: 'stable',
};
const context = {
environment: 'production',
tenant: 'acme',
cohort: 'experiment-b',
};resolver 将两者变成一个具体、不可变结果,例如版本 2.4.3、唯一 remote 名称、版本化
mf-manifest.json 和 deployment ID。loader 不重新运行任何业务策略,只执行已经解析的 source。
Resolver 组合与 registry
Fronts 提供 createStaticResolver()(测试、本地与确定性 fallback)、createRegistryResolver()
(HTTP registry)、带 fresh/stale 窗口的 createCachedResolver()、顺序 fallback resolver 和可插拔
ResolutionCache/内存实现。默认 cache key 包含 name、expose、range、channel、environment、tenant
与 cohort;若自定义 metadata 参与版本选择,必须提供自定义 key,否则不同策略上下文可能误用同一决策。
内置 registry resolver 通过 GET 发送存在的 name, expose, range, channel, environment, tenant, cohort。最小响应包含 source,还可包含 version 和 metadata。认证 header、credential、endpoint
计算、fetch 与 payload decoding 均可注入。服务端必须认证 caller 并验证所有 policy input,浏览器 query
绝不能证明 tenant/cohort 成员身份。
基于解析结果规划容器
registry 返回具体部署后,mount 才能从 metadata 决定执行边界;planner 在同一 transaction 内、 container-specific loader 选择之前运行:
container: ({ identity, resolved }) => {
const frame = resolved.metadata?.frame;
if (typeof frame !== 'object' || frame === null) return { type: 'dom' };
const url = Reflect.get(frame, 'url');
const origin = Reflect.get(frame, 'origin');
if (typeof url !== 'string' || typeof origin !== 'string') {
throw new Error('Invalid iframe deployment metadata.');
}
return { type: 'iframe', src: url, targetOrigin: origin, title: identity.name };
};在构造 request 前必须校验外部 metadata。Fronts 会快照 request,通过 containerLoaders 选择
loader,并把同一份冻结 ResolvedApp 交给 prepare context,避免计划与执行使用不同决策。
Module Federation source 规则
@fronts/mf 接受官方 Remote 形状的 entry-based 或 version-based remote。它在调用者提供的 MF
instance 上注册具体 remote,根据 source 和规范化 ref 生成 remoteName/expose,调用
loadRemote(id, { from: 'runtime' }),把 null/异常映射为 Fronts load error,并在 preload 时调用
preloadRemote()。同一 instance 内,已观察到的 remote name 若绑定到不同 source 或已知版本会被
拒绝,除非调用者明确 force replacement。
优先 manifest,而不是裸 remote entry,因为 manifest 保留官方预加载、snapshot、类型提示和 DevTools 所需的资源及 shared metadata。Fronts 把这些内容当作 MF-owned opaque data,绝不修改 全局 snapshot。
版本、channel 与缓存策略
registry 应只用不可变已发布版本满足 semantic range;在服务端把 stable/canary/next channel 映射 到具体 deployment;以已认证 subject + experiment salt 确定 cohort;返回具体版本、不可变 URL 和 policy revision/deployment ID;在同一 MF instance 中不要复用 mutable remote name;至少在回滚窗口 内保留旧 artifact。Fronts 不规定 registry 数据库或 rollout 算法,这些属于独立可运维的 deployment plane。
缓存 fresh TTL 内直接返回;fresh 过期后 refresh 失败,才可在有限 stale TTL 内返回旧解析。它是 可用性行为,不是静默版本 fallback。每次使用 stale 都应发 telemetry,artifact 必须仍不可变可用, 且安全撤销不能被长 stale window 绕过;敏感应用需要 kill-switch 或极短 TTL。
预加载、安全发布与回滚
host.preload() 解析相同策略并请求 transport preload,不挂载、不创建 service scope,也不占用
container。MF preload promise 汇总资源成败;除非产品在导航前必须取得应用,否则 rejection 应视为
优化失败,而不是运行时已经不可用。
安全发布使用不可变 URL + Fronts replacement:registry 向目标 cohort 推广 B;Host 解析 B 并在
staging slot 挂载;B 通过协议和 readiness 后才 commit 并卸载 A;若 staging 失败,A 继续活跃;
registry 可降级 B,使后续解析返回 A 或修复后的 C。常规 rollout 不要对已活跃 remote 调
registerRemotes(..., { force: true }),因为官方 Runtime 会清理 loaded-module cache;唯一 remote
name 配合应用级 replace 更容易审计。
非目标与验证
Fronts 不发布 artifact、不签名 manifest、不生成类型、不运营 registry,也不选择 shared 版本。 core resolver/host 测试验证规范化、policy snapshot、缓存窗口、取消、preload 与 resolved decision; MF adapter 测试证明只调用官方公开注册、预加载和加载 API;replacement 测试证明 promotion/rollback。