DOM、CSS 与 sandbox
区分 DOM 所有权、样式隔离和 JavaScript realm,并理解它们与安全边界的区别。
三个独立决策
应用的行为取决于 JavaScript 在哪里执行、谁拥有 DOM 边界以及接收哪些样式。配置其中一个维度不会自动配置其他维度。
| JavaScript 模式 | 执行方式 | 用途与限制 |
|---|---|---|
module |
主窗口中的 import() |
可信的现代模块;不隔离宿主全局变量 |
strict |
在隐藏 iframe 内执行真实 import | 独立 realm 与清理;要求模块可在其中加载 |
eval |
iframe 内的传统 HTML/scripts 路径 | 兼容 UMD/IIFE;不像 strict 那样支持 ESM 模块 |
eval 模式通过 HTML 兼容路径在 iframe 内执行脚本;ESM 模块应根据所需 realm 使用 module 或 strict。
Strict 及其回退
await wu.init({
sandbox: 'strict',
strictFallback: false,
apps: [{ name: 'reports', url: '/apps/reports' }],
});
await wu.mount('reports', '#reports-slot');
console.table(wu.getSandboxInfo('reports'));
iframe 内 import 失败默认产生错误。strictFallback: true 明确允许降级到 eval 模式;它不会修复与该模式不兼容的 ESM bundle。应用级选项优先于全局选项。
getSandboxInfo 暴露 requestedMode、actualMode、isolationLevel、mounted、nativeShadow 和 domOwnership。诊断回退时比较 requestedMode 与 actualMode:配置表达期望,状态描述应用实际执行的模式。
谁拥有 DOM
domOwnership |
结果 |
|---|---|
wu |
WU 创建外层 ShadowRoot,并向 renderer 提供内部根节点 |
app |
renderer 管理自身边界,适用于 LitElement |
light |
挂载时不使用 WU 外层 ShadowRoot |
显式值优先。未设置时,nativeShadow: true 选择 app,false 选择 wu;两者都没有时,framework: 'lit' 选择 app,其余选择 wu。
名称 app 表达一种责任,不保证组件真的创建 Shadow DOM。如果 renderer 没有创建自身边界,内容仍处于它收到的 DOM 树中。
样式分发
配置应用 manifest:
{
"name": "reports",
"entry": "assets/reports.js",
"styleMode": "own-only"
}
| 值 | 含义 |
|---|---|
shared |
bridge 允许将外部样式分发到 ShadowRoot |
isolated / none |
不注入额外外部样式 |
fully-isolated / own-only |
注入被识别为属于该应用的样式 |
bridge 观察变化,并将样式归属到应用。宿主代码创建的样式表可以通过 wu.tagStyleAsApp(element, appName) 标记。不要假定 shell 的全局 CSS 规则能够穿越 ShadowRoot。继承的 custom properties 和可继承 CSS 属性仍可能影响内容外观。
sandbox 从 manifest 接收 styleMode。应在那里决定样式策略;宿主顶层配置中的同名字段不会在挂载时替代该值。
实际的信任边界
iframe 实现本身注明它与宿主同源,并将节点创建重定向到宿主文档。节点可能暴露 ownerDocument.defaultView,脚本可由此访问宿主。隐藏 parent 或 top 无法封闭此路径。
这些模式用于协调可信代码、全局变量和清理。执行不可信代码需要其他边界,例如隔离的源与受限协议;运行时的同源 iframe 仍保留潜在的宿主访问能力。
容器与布局
slot 应是 renderer 独占的区域。在 React/Vue 中,将 loading 信息放在挂载节点旁边:如果 shell 在同一节点内部协调其子节点,可能删除 WU 插入的树。仓库中专门的 Vue 测试重现了这种无报错故障。
宿主配置中的 fullBleed 决定微前端是否占满 slot 高度并负责自身滚动。如果内容应随文档自然流动,保留默认行为。slot 高度和布局仍由 shell 负责。
实现参考
模式:src/core/wu-core.js、src/core/wu-core.js、src/core/wu-core.js、src/core/wu-core.js;所有权:src/core/wu-sandbox.js;同源限制:src/core/wu-iframe-sandbox.js。测试:tests/unit/sandbox-honesty.test.js、tests/unit/native-shadow-sandbox.test.js、tests/unit/sandbox-container-ownership.test.js、tests/unit/style-own-only.test.js、tests/unit/style-cross-app.test.js、tests/unit/vue-slot-mount-target.test.js。
在 strict 中,parent.postMessage 遵守 targetOrigin,并将 sandbox 窗口作为 event.source。内部访问 __wuHostPostMessage 已移除。该身份修复不意味着同源 iframe 能隔离恶意代码。