Skip to content
返回维护与 LTS

破坏性变更处理

识别、分类并吸收上游发布的破坏性变更,无需救火。

为什么

破坏性变更只在触及你实际运行的代码时才破坏;多数团队过度反应,重写 changelog 提到的所有东西。有纪律的做法是把每条破坏性变更映射到代码库中的爆炸半径 — 哪些入口、哪些测试、哪些功能 — 只吸收那些。这把吓人的"200 条破坏性变更"changelog 变成可处理的"其中 7 条触及我们代码"清单。分类还让你排序:纯重命名可 codemod 且便宜,行为变更需测试,移除的 API 需设计替代。跳过分类是升级花数周而非数天的原因。

何时使用

任何大版本升级期间,或依赖在小版本中发破坏性变更(pre-1.0 包中不幸常见)。

如何做

1. 从 changelog 把每条破坏性变更提取到表格:ID | 描述 | 类型 | 爆炸半径
2. 分类类型:rename(codemod)| removed-API(替代)| behavior-change(测试)| config-required(配置)
3. grep 代码库中每个移除/重命名的符号以测爆炸半径;零命中的行删掉
4. 按风险排序:先重命名(机械),再配置,再移除 API,最后行为变更
5. 每条先写一个失败的测试演示破坏,再修到绿(用 TDD 做升级)
6. 每条破坏性变更单独提交,使 git bisect 能把未来回归隔离到具体变更

示例

# 破坏性变更跟踪表(升级 PR 中的 markdown 表)
| ID | 类型          | 符号              | 命中 | 动作                |
|----|---------------|-------------------|------|---------------------|
| 1  | rename        | ReactDOM.render   | 3    | codemod -> createRoot |
| 2  | removed-API   | componentWillMount | 0    | 跳过(零命中)      |
| 3  | behavior      | useEffect 跑两次  | 12   | 加 StrictMode 测试  |
| 4  | config        | concurrent mode   | 1    | 在 root 设置        |

# Codemod 重命名
npx @codemod/cli --plugin react-18 src/

# TDD 一条行为变更:StrictMode 双调用 effect
it("effect 在 StrictMode 下幂等", () => {
  // ... 修复前失败,修复后通过
});

常见问题

  • ⚠把所有破坏性变更同等对待 — 重写 changelog 提到但你实际不调用的代码,浪费数天。
  • ⚠无爆炸半径分析 — 在生产运行时才发现移除的 API,因为从没 grep。
  • ⚠一个 mega-commit 修所有破坏性变更 — git bisect 无用,回归无法隔离。

最佳实践

  • ✓修前先 grep — 零命中的破坏性变更可免费跳过,多数 changelog 80% 可跳。
  • ✓每条破坏性变更单独提交,使 bisect 能把未来回归钉到确切的上游变更。
  • ✓每条行为变更先写失败测试 — 测试记录破坏并证明修复。