# 比较影子版本

运行隐藏副本，比较 WU 输出并了解比较范围。

本页介绍 WU Framework `4.0.0`。升级现有项目之前，请阅读 [Framework 4.0 与 CLI 1.2 迁移指南](/zh-cn/docs/guides/releases/)。

主应用保持可见和已挂载状态。`wu.shadow` 挂载隐藏且不可交互的副本，复制经过 WU 的输入并记录门面输出。可在替换可见应用前比较重写或更新版本。

```js
import { wu } from 'wu-framework/core';
import 'wu-framework/shadow';

// cart must already be registered and mounted.
await wu.shadow.start('cart', { url: '/apps/cart-v2/', rpcTimeout: 5000 });
try {
  await wu.update('cart', { currency: 'EUR' });
  const report = wu.shadow.report('cart');
  console.log(report.equal, report.dom, report.outputs);
} finally {
  await wu.shadow.stop('cart');
}
```

<span id="entradas-y-salidas"></span>

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

## 输入与输出

副本接收 props、事件和 store 读取，其写入使用独立覆盖层。RPC 或契约调用会获得主应用针对相同通道和参数记录的响应。副本的 `emit`、`handle` 和 `provide` 被记录，但不会通过 WU 发布其效果。

比较覆盖门面操作，不会拦截所有浏览器副作用。副本代码直接执行的 `fetch` 或外部写入仍由该应用负责。它也不会重放用户点击，不能证明视觉布局等价。

<span id="leer-el-informe"></span>

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

## 读取报告

`report().dom` 比较去除内部属性后的规范化树；`outputs` 比较记录的操作与参数。`equal` 表示这些比较未发现差异。`unmatchedCalls` 标记无匹配调用；超过 `rpcTimeout` 后返回 `WU_SHADOW_NO_TWIN_CALL`。这不等于自动批准部署。

`start` 返回初始报告；`report` 返回当前报告或 `null`；`stop` 释放副本、钩子及等待任务并返回最终报告；`sessions` 列出会话。主应用必须已挂载，重复创建影子会返回 `WU_SHADOW_EXISTS`。副本保留主应用授权，默认注册名为 `<app>~shadow`，可通过 `name` 修改。

<span id="interceptar-operaciones-del-host"></span>

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

## 从宿主拦截操作

```js
const release = wu.intercept('cart', (kind, args, next) => {
  if (kind === 'store.set') console.log('cart writes', args[0]);
  return next(...args);
});
// Remove the middleware when the host no longer needs it.
release();
```

`intercept` 返回清理函数。`next(...args)` 继续操作；返回其他结果则替代操作。多个拦截器按注册顺序执行。必须保留应用所期望的同步或异步契约。

当 props 更新未到达 twin 时，shadow 报告包含 `props.failures`。存在这些故障时，`equal` 为 `false`；不要将部分比较视为部署等价。