portal/skills/ui.engineering.principles.v1.md

4.2 KiB
Raw Permalink Blame History

UI Engineering Principles v1for Code Agents

目标:在不指定框架/库细节的前提下,让 agent 自主做正确的 UI 工程决策。 输出要求:每次改动必须同时满足 可维护 / 可测试 / 可演进 / 可回滚。

  1. 先决策再动手Decision Log

在修改前agent 必须在 PR 描述或注释里输出一段 Decision Log最多 10 行):

组件边界如何划分(为什么)

状态放哪(为什么)

哪些是公共骨架,哪些是 slot/children 兼容性策略(是否破坏现有 API 风险点与回滚点

不求长,但求明确。没有 Decision Log 视为不合格提交。

  1. 组件设计准则(边界与组合) 2.1 单一职责

一个组件只负责一个“稳定职责”

如果组件名需要用 “And/With/Plus” 连接多个职责 → 必须拆分

2.2 优先 Composition组合而不是 Config配置

优先通过 children / slots 组合 UI 结构

禁止为“结构差异”引入大量 boolean/enum props

只有在“结构稳定但样式/行为轻微差异”时才允许 variant

2.3 公共骨架 + 可插拔区域

抽取稳定的 Layout Skeleton 为 Root/Wrapper

差异点必须落在 children/slotsHeader/Nav/Footer/Actions 等)

  1. 状态管理准则(少、近、可注入) 3.1 状态最小化

不新增“可从现有数据推导”的 state用 derived/computed

不新增“只服务渲染”的 state用 CSS/DOM 或 memo

3.2 状态就近原则

UI 局部状态open/collapsed/hover放组件内部

跨多个子组件共享但局部范围内 → Context组件树内

全局业务状态 → store/server仅必要时

3.3 可测试性要求

关键 UI 状态必须可通过 props 注入或通过 context mock

逻辑优先放 hook视图保持“纯 render”

  1. 样式与可覆盖性(不锁死) 4.1 className 可组合

所有可复用组件必须接受 className 并合并

禁止写死样式导致无法覆盖(除非明确是私有组件)

4.2 语义优先

使用语义标签nav/aside/header/main/button

可交互元素必须可键盘操作button/link不用 div 冒充)

4.3 选择器稳定

使用 data-* 或有限的 class 作为状态标记(如 collapsed/active

避免复杂层级选择器导致脆弱

  1. 兼容性与演进(不破坏用户) 5.1 默认向后兼容

任何改动尽量不破坏旧 APIprops/DOM 结构/路由)

若必须破坏:提供迁移方式或兼容层,并在说明中写清

5.2 小步可回滚

每个提交尽量原子化Atomic Commit

重构必须可分阶段:先抽公共,再迁移,再清理旧代码

  1. 性能准则(先可读,后优化) 6.1 不做“预优化”

禁止在没有证据时引入复杂 memo/useCallback/useMemo

若新增 memo必须说明为什么必要避免不必要渲染/昂贵计算)

6.2 可见性能问题再优化

性能优化必须是“局部、可验证、可回滚”的

  1. 测试准则(最小但关键) 7.1 测试优先覆盖“行为”,不是“实现”

测试用户可感知行为:导航高亮、折叠、权限可见性等

不测试内部实现细节class 名、组件层级等)

7.2 最小覆盖要求

重构 UI至少补 1 个关键路径测试unit 或 integration

引入新状态/交互:必须有测试覆盖

  1. 文档与可读性(未来的你也是用户) 8.1 代码即文档

组件 API 清晰可读prop 名可解释)

复杂逻辑提取为函数/hook并用短注释解释“为什么”

8.2 禁止“聪明代码”

避免迷宫式条件渲染

避免过度抽象(抽象必须带来复用或一致性收益)

  1. 输出格式要求agent 必须遵守)

每次提交/变更输出:

Decision Log≤10 行)

变更摘要(改了什么)

风险点(可能破坏什么)

验证方式(如何验证:命令 + 预期)

回滚方式(如何快速退回)

  1. 最终验收Self-check

Agent 在结束前必须自检并明确回答(是/否):

是否减少了重复,而不是引入更多分支?

是否让新增需求更容易通过组合实现?

是否状态更少、更近、更可测?

是否可覆盖样式并保持语义化?

是否可回滚(原子提交/分阶段)?

任意一项为“否”,必须解释原因或调整实现。