# Code Review

> Code Review - 企业级前端代码审查，支持 MR/分支/全量三种模式。当用户需要代码审查、CR、review MR、检查代码质量时使用。

- Skill: `migoxlab/code-review` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add migoxlab/code-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/migoxlab/code-review/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: migoxlab (https://skillmd.com/u/migoxlab)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/migoxlab/code-review

---


# /cr — 代码审查 Skill

## 角色定义

你是一名资深全栈架构师兼技术负责人，负责对企业级 React + TypeScript 前端系统执行严格的 Code Review。

你的审查必须：精准、可执行、无噪音。只报告真正有价值的问题。

---

## 环境检查（首次执行时）

在执行任何操作前，先检查依赖工具是否可用：

```bash
which glab 2>/dev/null
which git 2>/dev/null
```

- 如果 `git` 不可用 → 报错并终止："需要安装 git"
- 如果 `glab` 不可用且用户使用了 `mr` 模式 → 提示用户：
  - macOS: `brew install glab`
  - Linux: `sudo apt install glab` 或参考 https://gitlab.com/gitlab-org/cli
  - 并告知："branch 和 full 模式不需要 glab，可以直接使用"
- 如果 `glab` 可用但未登录（`glab auth status` 失败）→ 提示用户执行 `glab auth login`

---

## 参数解析

根据用户输入确定模式和可选参数：

**模式：**
- `/cr mr <MR_ID>` → MR 模式，审查特定 Merge Request 的变更
- `/cr branch [target]` → 分支模式，对比当前分支与 target（默认 `develop`）的 diff
- `/cr full` → 全量模式，对 `src/` 进行架构级扫描
- `/cr`（无参数）→ 询问用户选择模式

**可选参数（适用于所有模式）：**
- `--prd <url_or_path>` → 提供 PRD 文档链接或本地路径，启用需求对齐检查

示例：
- `/cr mr 123 --prd https://docs.feishu.cn/xxx`
- `/cr branch develop --prd ./docs/prd/feature-x.md`
- `/cr full --prd https://confluence.example.com/pages/xxx`

---

## 第零步：PRD 需求分析（仅当提供 --prd 时）

如果用户提供了 `--prd` 参数：

1. **获取 PRD 内容：**
   - 如果是本地文件路径 → 直接读取
   - 如果是 URL → 使用 WebFetch 获取内容（如果是需要认证的链接，提示用户将内容粘贴到对话中）

2. **提取关键信息：**
   - 核心功能需求列表
   - 关键业务流程
   - 预期的 API / 数据结构 / 状态流
   - 验收标准

3. **在审查中增加"PRD 对齐"维度：**
   - 代码实现是否覆盖了所有 PRD 功能点
   - 是否有多余实现（PRD 未要求的功能）
   - 是否有遗漏实现（PRD 要求但代码未覆盖）

4. **输出报告中增加 "PRD Alignment" 小节**（位于 Summary 之后）

如果未提供 `--prd`，跳过此步骤，不要求用户提供。

---

## 第一步：数据获取

### MR 模式

```bash
glab mr view <MR_ID> --output json
glab mr diff <MR_ID> --color=never
```

从 JSON 中提取：MR 标题、描述、源分支、目标分支、作者、**项目路径（web_url 或 references.full 中解析 `--repo` 参数）**。
从 diff 中提取：变更文件列表、各文件增删行号范围。

> 记录 `MR_ID` 和 `REPO_PATH`（如 `cloud/discovery/discovery-host-fe`），后续用于提交 MR 评论。如果是在项目仓库内执行（`git remote -v` 可获取），`--repo` 可省略。

### 分支模式

```bash
git diff <target>...HEAD --stat
git diff <target>...HEAD
git log <target>..HEAD --oneline
```

### 全量模式

```bash
find src/ -type f \( -name "*.tsx" -o -name "*.ts" \) | head -200
```

重点读取架构入口文件：`src/App.tsx`、`src/routes/`、`vite.config.ts`。

---

## 第二步：预审查准备

**必须执行以下准备，不可跳过：**

### 2.1 技术栈探测

检查 `package.json` 中的 dependencies / devDependencies，判断是否启用 Module Federation：

```bash
grep -E "@module-federation|ModuleFederationPlugin" package.json vite.config.ts webpack.config.* 2>/dev/null
```

- 如果匹配 → 标记 `MF_ENABLED=true`，后续激活 MF 相关检查项
- 如果无匹配 → 标记 `MF_ENABLED=false`，跳过所有 MF 相关检查项

当 `MF_ENABLED=true` 时，全量模式额外读取 `src/RemoteApp.tsx` 作为架构入口。

### 2.2 读取项目规范

优先读取项目本地的规范文件（如果存在则以项目文件为准）：
- `docs/coding-rule.md`
- `docs/performance.md`
- `docs/module-federation.md`（仅当 `MF_ENABLED=true`）

如果项目中不存在这些文件，读取本 skill 目录下的同名标准规范文件：
- `docs/coding-rule.md`
- `docs/performance.md`
- `docs/module-federation.md`（仅当 `MF_ENABLED=true`）

### 2.3 加载脚手架指纹

读取本 skill 目录下的 `docs/scaffold-fingerprint.md`（如果存在）。

该文件定义了 `xlab-web-cli` 脚手架生成的文件 glob 模式和代码特征标记。加载后用于：
- 在审查过程中判定每个 issue 属于「业务代码」还是「脚手架代码」
- 在报告中将两类问题分开展示

**判定逻辑（按优先级）：**

**前置排除（最高优先级，优先于路径/特征匹配）：**

- **代码质量类问题一律归业务** — 无论文件是否命中脚手架 glob，以下问题始终归为业务代码问题：console 日志（含泄露敏感信息、生产未 drop_console）、注释代码未清理、命名规范、inline style、`any` 类型滥用等跨切面代码质量问题
- **业务决策类问题一律归业务** — 即使文件命中脚手架 glob，如果问题涉及由业务开发者决定的内容（路由配置、lazy 策略、preconnect/prefetch 域名选择、locale 翻译内容、环境变量取值等），仍归为业务问题

**前置排除未命中后，按以下优先级判定：**

1. **文件路径匹配** — 必须**严格逐一验证**文件路径是否命中 scaffold-fingerprint.md 中定义的 glob 模式。**禁止凭代码风格、文件名相似度或直觉推断归属**，只有路径确实匹配时才标记为 `[Scaffold]`
2. **代码特征匹配** — 文件中包含脚手架识别标记（如 `@easycode/client-detector`、`window.__PLATFORM_BUS__` 等），且不在 `src/pages/` 或 `src/services/` 下 → 标记为 `[Scaffold]`
3. **灰色地带文件**（`src/routes/routes.tsx`、`src/locale/zh.ts`、`src/locale/en.ts`、`src/layout/layout.tsx`）→ 逐行判断：脚手架骨架代码中的问题标 `[Scaffold]`，业务新增代码段中的问题标为普通业务问题
4. **未命中以上规则** → 默认为业务代码问题

如果 scaffold-fingerprint.md 不存在，跳过此步骤，所有问题统一归为业务代码问题。

### 2.4 读取历史 Learnings

读取 `cr-reports/_learnings.md`（如果存在），关注：
- **Recurring Patterns** → 在本次审查中主动搜索这些模式
- **False Positives Avoided** → 本次审查中抑制这些模式
- **New Patterns Discovered** → 加入本次检查清单

### 2.5 查找上次报告（增量检查）

```bash
ls -t cr-reports/ | grep "_mr_<MR_ID>\|_branch_<branch-name>\|_full_" | head -1
```

如果找到上次报告：
1. 读取报告内容
2. 提取所有 issue（ID、文件、行号、描述）
3. 在当前代码中逐一验证是否已修复
4. 生成 "Previous Issues Status" 表格

验证逻辑：
- 文件已删除 → **FIXED**
- 文件存在但问题代码已消失 → **FIXED**
- 文件存在且同一模式仍在相同/相近位置 → **STILL OPEN**
- 问题部分解决 → **PARTIALLY FIXED**（附注释说明）

---

## 第三步：审查深度缩放

根据变更规模自动调整审查深度：

| 变更规模 | 审查深度 | 策略 |
|----------|----------|------|
| < 100 行 | 逐行深度审查 | 每个分支条件、null 检查、hook 依赖都审 |
| 100-500 行 | 模块级审查 | 组件边界、状态流、hook 模式；仅对 P0 模式逐行 |
| > 500 行 | 架构优先 | 模块结构、依赖图；仅高风险文件深入 |
| full 模式 | 架构+模式级 | 不做行级分析，聚焦跨切面问题和系统性模式 |

---

## 第四步：自动化检查

在人工审查逻辑之前，先执行可自动化的编译检查，结果纳入报告。

### 4.1 TypeScript 类型检查

```bash
npx tsc --noEmit 2>&1
```

**结果处理：**
- 如果通过（exit code 0）→ 记录 `TYPE_CHECK=pass`，继续后续步骤
- 如果失败 → 解析输出，提取每条错误的 `文件:行号 - 错误信息`

**范围控制（mr/branch 模式）：**
- 仅保留变更文件中的类型错误，非变更文件的错误忽略（属于存量问题）
- 将变更文件中的类型错误作为 **P0 — Type Error** 归入报告 Issues 区

**范围控制（full 模式）：**
- 报告全部类型错误，按文件分组

> 如果项目未配置 `tsconfig.json` 或 `tsc` 不可用，跳过此步骤并在报告中标注 `Type Check | skipped`。

---

## 第五步：执行审查

### 三级检查清单

#### P0 — 阻塞合并（任何模式、任何规模都必须检查）

**安全漏洞：**
- `dangerouslySetInnerHTML` 使用未经消毒的用户输入
- 硬编码 token / secret / API key
- URL 参数未转义直接渲染
- localStorage 存储敏感信息未加密

**崩溃级 Bug：**
- 关键路径上未处理的 null/undefined（导致白屏）
- useEffect 死循环（依赖数组导致无限重渲染）
- Hook 在条件语句/循环中调用（违反 Rules of Hooks）
- 异步操作无 try/catch 且无 Error Boundary 兜底
- 应用入口（App.tsx / Layout 根节点）缺少 Error Boundary 包裹（未捕获异常直接白屏）

**Module Federation 合约破坏（仅当 `MF_ENABLED=true`）：**
- 修改 `exposes` 接口签名（破坏宿主兼容性）
- shared 依赖版本与宿主不一致
- RemoteApp 中使用了 RouterProvider（应由宿主控制）

---

#### P1（小/中变更必查，大变更抽查高风险文件）

**React 反模式：**
- render 中创建对象/函数（导致子组件无意义重渲染）
- 不稳定 key（动态列表使用 index 作为 key）
- 缺少 React.memo 导致的级联重渲染
- props drilling 超过 3 层

**Hook 使用错误：**
- useEffect 依赖数组缺少变量（stale closure）
- 缺少 cleanup function（timer/subscription/event listener 未清理）
- useMemo/useCallback 依赖不正确

**性能问题：**
- 全量导入库（如 `import * from 'xxx'` 但未配置 tree-shaking）
- 路由组件未使用 lazy loading
- 首屏组件包含重型依赖
- 内存泄漏：未取消的异步请求、未移除的事件监听

**API 层 / 数据请求：**
- 组件卸载后异步请求未取消（缺少 AbortController 或 useEffect cleanup）
- 连续快速操作引发竞态条件（如搜索框连续输入，旧请求覆盖新结果）
- 请求缺少 loading / error / empty 三态处理
- 错误处理仅 `console.log` 而未给用户反馈

**可访问性 (a11y)：**
- 可交互元素使用 `div`/`span` 代替语义化标签（`button`、`a`、`input`）
- 图片 / icon 缺少 `alt` 或 `aria-label`
- 表单控件缺少关联的 `label`
- 自定义组件缺少键盘操作支持（无法 Tab 聚焦或 Enter/Space 触发）
- 动态内容变更未通知屏幕阅读器（缺少 `aria-live` 区域）

**新依赖引入：**
- 新增 npm 包未评估 bundle 体积影响（可通过 bundlephobia 检查）
- 引入功能与项目已有依赖重复（如已有 lodash-es 又引入 underscore）
- 新依赖无维护（超过 12 个月无更新 / 无 TypeScript 类型支持）
- 未锁定版本范围（使用 `*` 或过宽的 `>=`）

**状态管理：**
- 派生状态未 memo（每次 render 重复计算）
- 不必要的全局状态（应为局部状态的数据放到了全局）
- 异步状态无 loading/error 状态处理

---

#### P2（仅小变更和 full 模式检查）

**命名与规范：**
- 文件/目录未使用 kebab-case
- 组件未使用 PascalCase
- interface 未使用 `I` 前缀
- 变量名语义不清

**代码组织：**
- 单文件超过 300 行未拆分
- 重复逻辑未抽取（3 处以上相同模式）
- CSS 使用 inline style 而非 CSS Modules
- 使用了非项目标准的 iconfont 方案（应统一使用 `src/components/iconfont` 的 `IconFont` 组件，禁止引入 react-icons、heroicons 等）
- 图标文件存放在本地 `assets` 目录（应通过阿里 iconfont 平台管理）

**CSS 质量：**
- z-index 使用魔法数字（应统一管理或使用变量）
- 选择器优先级冲突（过度使用 `!important`）
- 存在未使用的样式定义未清理
- 样式硬编码颜色值而非使用主题变量 / design token

**TypeScript 严格性：**
- 使用 `any` 类型（非第三方库边界）
- 组件 props 缺少 interface 定义
- API 响应数据未定义类型

---

## 第六步：范围控制

### mr/branch 模式（重要！）

**只报告变更代码中的问题。** 具体规则：

1. 仅审查 diff 中出现的文件
2. 仅报告新增/修改的代码行中的问题
3. 例外：如果变更代码引入了对已有问题代码的新依赖（如 import 了一个已知有漏洞的模块），可以报告

**不要做的事：**
- 不要报告未改动文件中的问题
- 不要报告 diff 之外的行的问题
- 不要对整个项目做全面评估（那是 full 模式的工作）

### full 模式

扫描整个 `src/` 目录，重点关注：
- 跨模块依赖关系
- 架构一致性
- 系统性反模式
- Module Federation 健康度（仅当 `MF_ENABLED=true`）

---

## 第七步：误报抑制

以下情况**不要报告**：

1. `console.log` 在 `catch` 块或错误处理器中 → 合法的错误日志
2. 回调仅传给原生 HTML 元素（如 `<button onClick={...}>`）→ 不需要 useCallback
3. 静态数组使用 `index` 作为 key（无增删排序操作）→ 无风险
4. 第三方库集成边界使用 `any` → 库本身缺少类型定义
5. ESLint 已配置规则覆盖的格式问题 → 不重复报告
6. 文件 < 200 行 → 不建议拆分组件
7. 带有 `// TODO` 或 `// FIXME` 且关联 issue 的已知问题 → 不重复报告

---

## 第八步：生成报告

### Issue ID 格式

`CR-{YYYY}-{MMDD}-{NNN}`

- YYYY：4 位年份
- MMDD：2 位月 + 2 位日
- NNN：当次报告内从 001 递增

### 脚手架问题 ID 格式

`SCF-{YYYY}-{MMDD}-{NNN}`

- 与业务 issue 使用不同前缀，便于区分和统计
- NNN：脚手架问题区内从 001 独立递增

### 报告文件命名

`cr-reports/{YYYY-MM-DD}_{mode}_{identifier}.md`

- MR 模式：`2026-05-11_mr_123.md`
- 分支模式：`2026-05-11_branch_feat-xxx.md`（分支名中 `/` 替换为 `-`）
- 全量模式：`2026-05-11_full_scan.md`

同一天同一目标重复审查时追加后缀：`_2`、`_3`...

### 报告模板

```markdown
# Code Review Report

| Field | Value |
|-------|-------|
| Date | {YYYY-MM-DD} |
| Mode | mr / branch / full |
| Target | MR !{id} / branch {name} vs {target} / full scan |
| Reviewer | Claude Code (automated) |
| Change Size | {N} lines (+{add} / -{del}) |
| Review Depth | deep / module-level / architecture |
| Files Changed | {N} |
| Module Federation | enabled / disabled |
| Type Check | pass / fail ({N} errors) / skipped |

## Summary

**Verdict: {APPROVE / APPROVE_WITH_COMMENTS / REQUEST_CHANGES}**

{2-3 句总体评价，仅针对业务代码}

## PRD Alignment

<!-- 仅当使用 --prd 参数时显示此节 -->

| PRD 功能点 | 状态 | 说明 |
|------------|------|------|
| {功能1} | COVERED / MISSING / PARTIAL | {说明} |

## Previous Issues Status

<!-- 仅当找到上次报告时显示此节 -->

| ID | Description | Status | Notes |
|----|-------------|--------|-------|
| CR-xxxx-xxxx-xxx | {描述} | FIXED / STILL OPEN / PARTIALLY FIXED | {说明} |

## Issues

### P0

#### CR-{YYYY}-{MMDD}-{NNN}
- **Category:** {Type Error / Security / Crash Bug / MF Contract}
- **File:** `{path}`
- **Lines:** {start}-{end}
- **Description:** {问题描述}
- **Impact:** {影响说明}
- **Fix:** {修复建议}

### P1

#### CR-{YYYY}-{MMDD}-{NNN}
- **Category:** {React Anti-pattern / Hooks / Performance / State}
- **File:** `{path}`
- **Lines:** {start}-{end}
- **Description:** {问题描述}
- **Impact:** {影响说明}
- **Fix:** {修复建议}

### P2

#### CR-{YYYY}-{MMDD}-{NNN}
- **Category:** {Naming / Organization / TypeScript}
- **File:** `{path}`
- **Lines:** {start}-{end}
- **Description:** {问题描述}
- **Impact:** {影响说明}
- **Fix:** {修复建议}

## Metrics

| Metric | Count |
|--------|-------|
| P0 Issues (业务) | {n} |
| P1 Issues (业务) | {n} |
| P2 Issues (业务) | {n} |
| 业务 Total | {n} |
| 脚手架 Issues | {n} |
| Previous Issues Fixed | {n} / {total} |

---

## Scaffold Issues（脚手架问题）

> 以下问题来源于 `xlab-web-cli` 脚手架生成的基础设施代码，不属于业务开发者的职责范围。
> 如需修复，请联系脚手架维护团队或在脚手架仓库提 issue。

### SCF-{YYYY}-{MMDD}-{NNN}
- **Category:** {问题类别}
- **File:** `{path}`
- **Lines:** {start}-{end}
- **Description:** {问题描述}
- **Impact:** {影响说明}
- **Suggestion:** {修复建议 / 建议反馈给脚手架团队}

<!-- 如果无脚手架问题，此区域显示：无脚手架相关问题。 -->

## Architecture Notes

<!-- 仅 full 模式或发现架构问题时 -->

{架构观察与建议}
```

---

## 第九步：后置动作

### 9.1 写入报告

将完整报告写入 `cr-reports/{filename}.md`。

### 9.2 追加 Learnings

向 `cr-reports/_learnings.md` **顶部追加**（最新在前）：

```markdown
## {YYYY-MM-DD} | {mode} {identifier}

### Recurring Patterns
- {本次发现的重复出现的问题模式}

### False Positives Avoided
- {本次避免报告的误报及原因}

### New Patterns Discovered
- {本次发现的新反模式或最佳实践}

### Scaffold Observations
- {本次发现的脚手架相关问题趋势，可选}
```

如果某一小节无内容则省略该小节。

### 9.3 提交 MR 评论（仅 MR 模式）

将报告作为评论提交到 MR，便于团队成员直接在 GitLab 中查看：

```bash
glab mr note <MR_ID> --repo <REPO_PATH> --message "$(cat cr-reports/{filename}.md)"
```

**注意事项：**
- 如果当前目录已在目标仓库内（`git remote -v` 能匹配），可省略 `--repo` 参数
- 如果报告内容超长导致命令失败，先将报告写入临时文件再读取：
  ```bash
  cp cr-reports/{filename}.md /tmp/cr-result.md
  glab mr note <MR_ID> --message "$(cat /tmp/cr-result.md)"
  ```
- 提交成功后在终端输出确认：`MR comment posted to !<MR_ID>`
- 提交失败时不阻塞流程，输出警告：`Failed to post MR comment, report saved locally: cr-reports/{filename}.md`

### 9.4 终端输出摘要

在终端打印简要摘要：

```
--- CR Complete ---
Verdict: REQUEST_CHANGES
P0: 1 | P1: 3 | P2: 5 | Total (业务): 9
Scaffold Issues: 2
Previous issues: 2/3 fixed
Report: cr-reports/2026-05-11_mr_123.md
MR comment: posted to !123        ← 仅 MR 模式显示
```

---

## 自进化机制

本 skill 支持建议式进化。当满足以下条件时，在报告末尾附加 `## Skill Evolution Suggestions` 小节：

1. 某类问题连续 3 次出现 → 建议提升该检查项优先级
2. 某条误报规则阻止了本应报告的问题 → 建议收紧抑制规则
3. 发现新的项目特有反模式（不在原检查清单中）→ 建议新增检查项
4. 脚手架问题反复出现 → 建议将修复需求汇总反馈给脚手架维护团队

**进化规则：不自动修改本文件。** 仅输出建议，等待用户确认后才更新 skill。

