其他语言版本:English | 当前网站:前端开发检查清单
本文不是代码规范,但会在一定程度上影响你的代码风格。
在 Code Review 新同学的代码时,有很多知识和细节需要反复解释。这份清单用于提交前自检,也用于 Review 时对齐标准。
使用原则:
- 提交 PR 前按清单完成一次自检
- CR 时用清单项说明问题,而不是只给出个人偏好
- 清单不是机械打分标准,优先关注业务边界、异常处理、可维护性和用户体验
- 确实需要违反某条规则时,应在 PR 描述中说明原因、影响范围和兜底方案
这份清单同时打包为 Claude Code / Kiro / Cursor / Codex 的 Skill,一条命令安装:
# Claude Code 全局
curl -fsSL https://github.com/wsafight/front-end-checklist/releases/latest/download/install.sh | sh -s -- claude
# 项目级:加 --local;卸载:加 --uninstall
# 其他工具把 claude 换成 kiro / cursor / codexWindows (PowerShell):
& ([scriptblock]::Create((irm https://github.com/wsafight/front-end-checklist/releases/latest/download/install.ps1))) -Tool claude安装脚本会校验 sha256、失败自动回滚、清理临时文件。安装后在对话里说 /frontend-checklist 或 "按前端清单 review" 即可触发审查。详见 Releases。
- 命名规范
- 数据与类型
- 函数设计
- 状态管理
- 控制流
- 异步处理
- 数据请求
- UI 与渲染
- 样式与响应式
- 路由与权限
- 性能
- 安全与健壮性
- 表单与交互
- 错误处理
- 测试
- 无障碍访问(a11y)
- 用户体验
- 代码质量
- 工程化
- 国际化(i18n)
- 日志与监控
- 依赖管理
- 浏览器兼容
- 文档与协作
- PR 自检
- 变量缩写必须得到团队认可,否则使用完整单词
- 常量全大写,单词间用下划线分隔,语义完整清晰
- 函数命名用
动词 + 名词,如sendSms;模板/JSX 中用handle + 名词 + 动词,如handleSmsSend - 善用
for、by、from、when、then等词表达函数意图
- 在数据边界处(接口响应、用户输入、路由参数、本地缓存、第三方 SDK 回调)检查数据是否存在及类型
- 减少不必要的类型默认转换与强制转换,优先分析数据为何不是预期类型
- 区分"缺失""为空""为 0""为空数组""为空字符串"的业务含义
- 布尔运算中明确
false、0、''是否与null、undefined语义相同 - 使用 TypeScript 时避免
any,合理定义类型和接口 - 优先用
interface描述对象结构,type用于联合类型等复合场景 - 函数参数和返回值都应有明确类型,避免隐式
any - 用联合类型、泛型、类型守卫表达真实约束,而不是绕过类型系统
- 在最小范围内声明数据对象
- 宽入严出:对接受的数据宽容,对输出的数据严格
- 持续拆分函数,直到每个函数只做一件事、能用一句话描述
- 函数返回值清晰统一,不要在同一函数中混用同步和异步结果
- 参数超过 3 个时改用对象传参
- 避免布尔参数,需要时用对象传参
- 钩子函数中只写调用,不写具体逻辑
- 不要轻易封装重复的业务代码,可能只是巧合而非真正重复
- 区分服务端状态和客户端状态,避免把接口数据无意义地复制到多个状态中
- 不存储可以稳定计算得到的派生状态
- 状态更新保持不可变,避免直接修改已有对象或数组
- 状态的来源、更新路径和消费范围要清晰,避免跨组件隐式共享
- 复杂状态优先集中到 reducer、状态机或专门的状态管理方案中
- 优先处理异常情况,再处理正常业务逻辑
- 条件判断和循环最多三层
- 判断顺序:先大范围(权限)再小范围(数据权限、业务判断)
- 复杂布尔运算加括号,方便他人阅读
-
if、else、for、while、do、switch、try、catch、finally的执行体无论多少行都加{ } - 注意差 1 错误,时刻区分
<=和< - 多用可提前终止的循环:
some、every、find(注意空数组时some返回false,every返回true)
- 不在同一语句中混用同步数据和异步数据
- 异步处理要考虑异常;Promise 必须通过
resolve或reject进入下一状态,避免卡死 - 不用
setTimeout解决异步问题,这会制造难以复现的 bug
- 每个请求都应考虑加载中、空数据、失败、重试和取消场景
- 避免重复请求,尤其是组件重复渲染、路由切换、依赖变化导致的请求放大
- 处理并发请求的竞态问题,避免旧响应覆盖新状态
- 明确接口错误和业务错误的处理方式,不要只判断 HTTP 状态码
- 接口响应进入页面前完成必要的归一化、兜底和字段兼容
- 写操作成功后应使相关查询缓存失效,避免读到过期数据
- 分页、无限滚动场景需处理重复数据、翻页竞态和边界去重
- 轻易不要手动操作 DOM
- 尽量不使用行内样式,即使通过 props 传递,也应在一定范围内传递 class
- 操作数组不需要返回值时用
forEach,而不是map - 不在渲染函数中修改数据
- 不在渲染函数中创建随机值(
Math.random()、Date.now()) - 不在渲染函数中发出网络请求
- 不在渲染中创建新组件,否则 React 会反复销毁并重建子组件树
- 列表渲染
key使用稳定唯一 id,不用数组下标或随机值 - 同一表单/输入控件不要在受控与非受控之间切换
-
useEffect/watch的依赖项必须完整,避免闭包捕获过期值 - 属性每个单独一行,方便阅读
- 页面需覆盖常见移动端、平板和桌面尺寸
- 长文本、超大数字、空数据、极端数据不能破坏布局
- 样式优先使用设计变量或统一约定,避免散落的魔法颜色和尺寸
- 交互状态需覆盖 hover、focus、active、disabled、loading
- 组件应避免依赖外层页面的偶然样式
- 页面权限、操作权限和数据权限需分别考虑
- 直接访问 URL、刷新页面、登录过期、权限变化时都应有合理兜底
- 路由参数需要校验,不要默认认为参数一定合法
- 未授权、无数据、资源不存在应展示不同状态
- 避免大数组进行查询等运算,用
Object、Map或Set优化 - 避免大量数据递归
- 程序要懒惰,不到最后一刻不获取或处理数据
- 没有明确性能瓶颈时,不做过早优化
- 图片/资源懒加载,避免首屏加载过多资源
- 对大组件、重计算、长列表和大型依赖进行按需加载或缓存优化
- 控制首屏资源体积,关注构建产物、依赖体积和关键路径资源
- 避免在循环中频繁操作 DOM 或触发重排
- 自定义字体设置
font-display策略,避免 FOIT/CLS - 第三方脚本延后加载(
defer/async/idle),不阻塞首屏
- 所有用户输入和外部输入都应基于业务规则进行验证
- 输入框根据业务添加长度、格式、范围、必填等限制
- HTML 标签和属性操作必须限定/过滤传入变量值,防止 XSS
-
dangerouslySetInnerHTML/v-html仅用于可信来源,且内容需先经过消毒 - 跨域写操作考虑 CSRF:使用 SameSite cookie 或 CSRF token
-
target="_blank"必须配rel="noopener noreferrer",防止反向 tabnabbing - 需要防嵌入的页面应通过
X-Frame-Options或 CSPframe-ancestors防点击劫持 - 不在前端存储敏感信息(token 存 httpOnly cookie,而非 localStorage)
- 定期检查第三方依赖安全漏洞(
npm audit) - 定时器和事件监听记得清除,否则可能引发内存泄漏
- 注重事物生命周期:初始化时创建,结束前清理
- 解决 bug 要分析根本原因,而不只是修复表象
- 对 API 调用保持敏感,尤其是低频调用变为高频调用的场景
- 表单校验规则应与后端约束保持一致
- 提交按钮应处理提交中、成功、失败和防重复提交状态
- 表单错误应定位到具体字段,而不是只给出笼统提示
- 危险操作需要二次确认或可撤销机制
- 用户操作后应有明确反馈,避免用户不知道操作是否生效
- 为关键业务模块添加错误边界,避免局部错误导致整个页面崩溃
- 接入错误上报系统,确保线上异常可被感知和追踪
- 捕获错误时保留必要上下文:接口、参数、用户操作路径和环境信息
- 不要吞掉异常,无法处理的错误应继续抛出或进入统一错误处理
- 核心业务逻辑必须有单元测试覆盖
- 组件测试关注行为而非实现细节
- 关键业务流程需要集成测试或端到端测试覆盖
- 修复 bug 时优先补充能复现该问题的测试
- 测试需覆盖正常、异常、边界、权限和空数据场景
- 交互元素(按钮、链接)必须有可读文本或
aria-label - 图片必须有
alt属性 - 表单控件必须有对应的
label - 页面可通过键盘完成核心操作
- 文本、背景、状态色需满足基本对比度要求
- 动态内容变化应通知屏幕阅读器(
aria-live) - 模态框打开时焦点应移入,关闭后应还原到触发元素
- 颜色不能作为传递信息的唯一手段
- 提示信息使用陈述句,不加语气助词和网络用语
- 错误提示应说明发生了什么,以及用户下一步可以做什么
- 空状态需给出明确含义和可执行的下一步
- 关键流程避免让用户重复输入已提供过的信息
- 删除、离开、覆盖、提交等不可逆操作应避免误触
- 避免魔法数字,用命名常量替代
- PR 提交前自我 review 一遍,不要依赖他人发现低级错误
- 优先使用
const,直到变量需要改变时再用let - 解构优先用于提升可读性,不为形式牺牲可读性
- 注释侧重 WHY:数据结构设计 > 不合理的业务逻辑 > 普通函数;不在注释中包含侮辱性词汇
- 用删除代替注释来精简代码
- 尽量不使用默认导出
- 减少不必要的依赖引入,开源库尽量只引入所需部分
-
package.json依赖项建议锁定版本号,避免使用^~ - 对引入的开源工具浅封装一层,降低未来替换成本
- 不要轻易复制代码;必须复制时手敲一遍,确保每行都理解
- 使用更新的语言特性提升程序健壮性
- 单文件行数应有限制(由团队自行定制)
- 业务功能不要依赖语言特性的隐式行为
- 提交前通过格式化、Lint、类型检查和必要测试
- 依赖变更需说明原因,并关注体积、安全性、维护状态和许可证
- 环境变量、构建配置、代理配置不能与本地环境强绑定
- 新增脚本、配置或目录时,命名应与现有项目结构保持一致
- 自动化校验尽量在 CI 中完成,避免只依赖人工检查
- 生产 source map 仅上传至错误监控平台,不随静态资源公开部署
-
.env等含敏感变量的文件不入库,改由.env.example声明所需字段
- 文案不硬编码,统一走翻译函数
- 日期、数字、货币格式根据 locale 处理,不手动拼接
- 避免拼接字符串构造句子,语序因语言而异
- 图片、图标中不嵌入文字
- 关键业务操作(支付、提交、权限变更)应有埋点
- 生产环境不输出敏感信息到 console
- 前端性能指标(LCP、FID、CLS)应可观测
- 错误上报应区分业务异常和程序异常,便于分类处理
- 埋点和日志中的手机号、身份证、邮箱等 PII 需脱敏或哈希
- 引入新依赖前先确认项目中是否已有等价能力
- 避免引入已停止维护的库
- 注意 license 兼容性(GPL 类库不能随意商用)
- 大体积依赖优先按需引入,避免全量打包
- 明确目标浏览器矩阵,并在构建工具(
browserslist、targets)中同步 - 新特性先做特性检测(
'IntersectionObserver' in window),不要做 UA 嗅探 - 按目标矩阵配置 polyfill,避免全量引入拖慢首屏
- 使用 CSS 新特性(
:has、容器查询、color-mix等)时考虑降级 - 核心页面需在目标浏览器上真机或等价环境验证
- 复杂组件/函数应有使用示例
- 破坏性变更(接口、props、事件名)需在 PR 中明确标注
- 公共 API 变更需同步通知依赖方
- 是否处理了加载中、空数据、失败、重试和无权限状态
- 是否处理了异常输入、边界数据和接口字段缺失
- 是否存在重复请求、重复渲染、内存泄漏或竞态问题
- 是否影响已有页面、路由、权限、埋点、接口契约或缓存逻辑
- 是否补充或更新了必要测试
- 是否需要更新文档、配置、示例或迁移说明