# DOM、CSS 与 sandbox

区分 DOM 所有权、样式隔离和 JavaScript realm，并理解它们与安全边界的区别。

<span id="tres-decisiones-distintas"></span>

<span class="section-anchor" id="section-1"></span>

## 三个独立决策

应用的行为取决于 **JavaScript 在哪里执行**、**谁拥有 DOM 边界**以及**接收哪些样式**。配置其中一个维度不会自动配置其他维度。

| JavaScript 模式 | 执行方式 | 用途与限制 |
| --- | --- | --- |
| `module` | 主窗口中的 `import()` | 可信的现代模块；不隔离宿主全局变量 |
| `strict` | 在隐藏 iframe 内执行真实 import | 独立 realm 与清理；要求模块可在其中加载 |
| `eval` | iframe 内的传统 HTML/scripts 路径 | 兼容 UMD/IIFE；不像 strict 那样支持 ESM 模块 |

`eval` 模式通过 HTML 兼容路径在 iframe 内执行脚本；ESM 模块应根据所需 realm 使用 `module` 或 `strict`。

<span id="strict-y-su-fallback"></span>

<span class="section-anchor" id="section-2"></span>

## Strict 及其回退

```js
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：配置表达期望，状态描述应用实际执行的模式。

<span id="quién-posee-el-dom"></span>

<span class="section-anchor" id="section-3"></span>

## 谁拥有 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 树中。

<span id="distribución-de-estilos"></span>

<span class="section-anchor" id="section-4"></span>

## 样式分发

配置应用 manifest：

```json
{
  "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`。应在那里决定样式策略；宿主顶层配置中的同名字段不会在挂载时替代该值。

<span id="la-frontera-de-confianza-real"></span>

<span class="section-anchor" id="section-5"></span>

## 实际的信任边界

iframe 实现本身注明它与宿主同源，并将节点创建重定向到宿主文档。节点可能暴露 `ownerDocument.defaultView`，脚本可由此访问宿主。隐藏 `parent` 或 `top` 无法封闭此路径。

这些模式用于协调可信代码、全局变量和清理。执行不可信代码需要其他边界，例如隔离的源与受限协议；运行时的同源 iframe 仍保留潜在的宿主访问能力。

<span id="contenedores-y-layout"></span>

<span class="section-anchor" id="section-6"></span>

## 容器与布局

slot 应是 renderer 独占的区域。在 React/Vue 中，将 loading 信息放在挂载节点旁边：如果 shell 在同一节点内部协调其子节点，可能删除 WU 插入的树。仓库中专门的 Vue 测试重现了这种无报错故障。

宿主配置中的 `fullBleed` 决定微前端是否占满 slot 高度并负责自身滚动。如果内容应随文档自然流动，保留默认行为。slot 高度和布局仍由 shell 负责。

<span id="referencia-de-implementación"></span>

<span class="section-anchor" id="section-7"></span>

## 实现参考

模式：`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 能隔离恶意代码。