
先聊个很多人没弄明白的事前端规范不是用来“限制”人的它是用来“救”人的。我见过太多项目前期跑得飞快代码随便写等到了第6个月、第8个月新需求来了改一个老功能要翻半天文件调一个bug顺便引入两个新bug团队成员之间互相看不懂代码git提交记录乱得像涂鸦墙。这时候大家才想起来补规范但已经来不及了欠下的技术债只能靠时间和加班还。所以“前端常用规范”这个词看着挺基础真正落实到位并持续执行的团队其实不多。今天这篇文章我就把一套经过多个项目沉淀、能直接落地执行的前端规范体系拆开来讲覆盖代码风格、Git提交、组件开发、接口协作这几条主线。无论你是刚带团队的技术负责人还是想给个人项目建立工程化底线的独立开发者这篇文章都能给你一份拿来即用的参考。1. 先想清楚前端规范到底在解决什么问题规范不是老板拍脑袋定的制度它本质上是在回答三个问题代码能否被快速读懂改动能否被安全执行协作能否不靠私聊。如果一套规范对这三个问题没有任何帮助那它就是在添乱。1.1 规范的本质是降低认知成本人脑的工作记忆非常有限一个方法里堆了七个变量、五个分支谁看谁懵。规范要做的就是把那些不必要的“阅读理解”省掉。比如约定组件props用驼峰、常量用全大写、事件回调以on开头别人看到变量名就知道它是什么、大概从哪来不需要再顺着代码往上翻。我见过不少团队觉得“我们自己能看懂就行”这种话在项目初期是对的等团队从2个人涨到8个人接手过多个模块之后再回头看这句话就是个笑话。真正的认知成本不只是写代码的人理解还包括code review的人理解、测试的人理解、两个月后的你自己理解。规范的存在就是让“理解代码”这件事只需要一次而不是每次都要从零开始。1.2 一套靠谱的规范体系都包含什么一个完整的前端规范体系通常拆成四个层面代码规范包括JavaScript/TypeScript语法风格、CSS类名规则、组件命名方式主要靠ESLint、Prettier、Stylelint这类工具强制约束。工程规范包括目录结构怎么组织、公共代码放哪里、组件如何分层这类规范靠团队约定和文档沉淀。协作规范包括Git提交信息格式、分支命名规则、Merge Request/Pull Request的检查项这是团队协作摩擦最多的地方。接口与数据规范包括接口文档怎么定义、传参格式怎么统一、错误码怎么处理直接影响前后端联调的效率。这四个层面缺一不可。代码规范管的是“写出来的东西像不像同一个人写的”工程规范管的是“东西放在哪、怎么组织”协作规范管的是“别人怎么接手你的工作”接口规范管的是“和外部系统的边界在哪里”。2. 代码风格规范让代码长得像同一个人写的代码风格是最容易自动化、也最容易见效的环节。核心思路就一句话能交给工具的事不要用人的自觉。2.1 JavaScript/TypeScript规范怎么落地现在再让人手工检查分号、引号、缩进那真是浪费生命。标准的做法是ESLint负责“代码质量问题”Prettier负责“格式问题”两者配合使用。我建议的基础配置组合是这样的{ scripts: { lint: eslint . --ext .js,.jsx,.ts,.tsx, lint:fix: eslint . --ext .js,.jsx,.ts,.tsx --fix, format: prettier --write . } }配合.eslintrc.js里几个关键的规则设置这些是经过多个项目验证后最不容易引发团队争吵的配置项module.exports { extends: [ eslint:recommended, plugin:typescript-eslint/recommended, prettier ], rules: { typescript-eslint/no-unused-vars: error, typescript-eslint/no-explicit-any: warn, no-console: warn, eqeqeq: [error, always], curly: error } };这里额外说明几个容易被忽略的细节no-explicit-any设成warn而不是error。理论上我们希望TypeScript项目里没有any但实际开发中总会遇到第三方库类型不完善、后端返回结构太复杂的情况。设成warn能在不阻塞开发的同时持续提示等有空闲了再逐步清理。eqeqeq一定要开。全等比较是JavaScript里最基础的防坑手段引发的隐式类型转换坑了多少人这里不展开但这条一定要从第一天就定死。no-console建议设成warn。不是说不能用console.log而是不允许代码提交时还遗留调试日志。如果团队有专门的前端日志监控系统可以把console.log替换成封装的logger方法再把这个方法加入白名单。Prettier的侧重点完全不一样它管的是“长得多好看”。建议直接在.prettierrc里配置一套固定的规则然后全员共用{ semi: false, singleQuote: true, trailingComma: none, printWidth: 100, arrowParens: always }2.2 CSS/HTML规范经常被忽视的重灾区很多团队的ESLint配置很完善但CSS完全是“自由生长”状态。我见过同一个按钮样式在十几个地方各写一遍也见过.class-a .class-b .class-c这种嵌套七八层的选择器改起来跟扫雷一样。CSS这一层我建议做三件事第一类名统一用BEM命名法。Block代表独立组件Element代表组件内部的子元素Modifier代表状态变化。/* 不推荐的写法 */ .panel-title-active {} /* 推荐写法 */ .panel__title--active {}第二用CSS变量统一设计变量。颜色、间距、字号、圆角这些全局值不要散落在各个文件里全部集中到:root变量中:root { --color-primary: #1677ff; --color-success: #52c41a; --spacing-base: 8px; --radius-md: 6px; }第三HTML标签和属性顺序保持统一。这种细节靠人记不现实直接交给eslint-plugin-html或prettier的插件处理。该加alt的地方必须加表单控件必须有label关联这些才是影响可访问性的硬指标。2.3 命名规范隐形的代码地图命名规范不用单独建文档它应该渗透在代码审查的每一个环节里。变量命名的基本约定布尔类型用is、has、can、should前缀如isLoading、hasPermission。数组用复数名词如users、list但list略宽泛能具体就具体。事件处理函数用handle前缀如handleClick、handleInputChange。组件的回调props用on前缀如onClick、onSubmit。文件命名方面React/Vue组件文件用PascalCase工具函数和hooks用camelCase配置文件、常量文件用kebab-case比如eslint.config.js这类。规则不用多但要全团队一致执行。注意命名规范最容易变成“写了但没人查”的摆设。只写在文档里不够要让它在ESLint里通过naming-convention规则生效或者至少在code review的检查清单里出现才会真正被执行。3. Git提交规范与协作规范规范最容易见效的入口代码风格规范提升的是代码可读性Git规范提升的则是整个团队的协作效率。如果你只能推行一套规范我首推Git提交规范因为它见效最快、反例最多、说服团队最容易。3.1 提交信息格式Conventional CommitsAngular团队提出的Conventional Commits规范到今天仍然是前端界最通用的提交格式type(scope): subject实际效果长这样feat(user): 新增用户详情页 fix(cart): 修复购物车数量异常 docs(readme): 更新部署文档 refactor(auth): 重构登录逻辑type的取值和含义需要统一这是最容易争论的地方。我建议参考约定式提交的官方定义固定成这张表type含义常见场景feat新功能新增页面、新增交互、新增接口调用fix修复bug修复样式错乱、修复逻辑异常docs文档变更README、注释、使用说明style代码格式格式化、去掉多余的逗号不涉及逻辑refactor重构代码逻辑调整但不改变功能和修复bugperf性能优化减少渲染次数、减小打包体积test测试新增测试用例、修改测试build构建相关修改webpack/vite配置、依赖升级chore其他改配置、换依赖、日常杂事配套还要用commitlint和husky硬性约束只有规则落到工具上才不需要靠人自觉npm install -D commitlint/cli commitlint/config-conventional huskyhusky配置在.husky/commit-msg里npx --no -- commitlint --edit $1commitlint.config.js的配置module.exports { extends: [commitlint/config-conventional], rules: { type-enum: [2, always, [ feat, fix, docs, style, refactor, perf, test, build, chore ]], subject-case: [0] } };3.2 分支管理与Merge Request检查项分支命名同样要有规律否则多人协作的时候光看分支名完全不知道在做什么。推荐格式功能分支feature/user-center修复分支fix/cart-bug发布分支release/1.2.0紧急热修分支hotfix/checkout-error代码合并进主分支之前必须过一遍Merge Request或者GitLab的Merge Request、GitHub的Pull Request。我建议每个MR模板里固定放这些检查项是否有无关代码改动比如只想修个bug结果带了8个文件格式变化。是否补充了必要的注释或文档TypeScript类型是否完整有没有滥用any是否考虑了异常分支网络错误、空数据、权限不足都要有处理。是否附带了自测结果截图或测试用例3.3 提交规范执行中的坑提交规范刚推行的时候最常见的问题是husky装上了但不生效。我这里说一个特别容易被坑的点husky的.git/hooks目录在npm install的时候会被覆盖所以一定要在package.json里加上prepare脚本{ scripts: { prepare: husky install } }不然你刚装好的hook可能几个人clone下来就失效了。另一个常见问题是已经写了一半的代码提交的时候被commitlint拦住了提示type不对。这时候不要直接--no-verify跳过那是拆了东墙补西墙。正确做法是先把提交信息改对如果改动比较复杂可以先git add分拣文件拆成多个语义清晰的提交。4. 组件与文档规范把复用门槛实实在在降下来团队自己的组件库和公共方法是最容易积累技术债的地方。比如两个人各写了一个格式化日期的工具函数一个用yyyy-MM-dd一个用YYYY-MM-DD有人封装了Modal组件有人直接在页面里写div弹窗。这些都是组件规范缺失的典型症状。4.1 组件设计的接口原则组件规范的核心不是规定“怎么写组件内部”而是规定“组件对外暴露的接口长什么样”。第一props尽量保持原子性。一个组件接收的props最好是原始数据字符串、数字、对象而不是另一个组件的渲染结果。比如一个表格组件应该接收columns配置和data数组而不是接收一个已经渲染好的ReactNode。这样组件的复用边界才清晰。第二允许覆盖但要有底线。组件要提供默认样式同时允许调用方通过className或style覆盖部分样式。这背后的原则是“合理的默认值有边界的自定义”。第三区分受控与非受控。以输入框为例如果组件内部维护状态那就是非受控组件如果值由父组件传入那就是受控组件。一个设计良好的组件应该同时支持两种用法这是React社区验证过的最佳实践Vue里通过v-model也能实现类似效果。4.2 组件文档的底线要求组件可以没有完整的Storybook文档站但至少要有一个能说清楚“怎么用”的README。我要求团队每个公共组件目录下必须包含这些内容组件功能的一句话描述。基础的代码示例至少覆盖一种常见用法。props表格包含类型、默认值、是否必填。已知问题和注意事项。示例如下# Button 按钮 基础按钮组件支持三种类型、两种尺寸。 ## 基础用法 \\\tsx import { Button } from /components/Button Button typeprimary sizemedium onClick{handleClick} 确认 /Button \\\ ## Props | 属性 | 类型 | 默认值 | 必填 | 说明 | | --- | --- | --- | --- | --- | | type | primary \| default \| danger | default | 否 | 按钮类型 | | size | small \| medium \| large | medium | 否 | 按钮尺寸 | | loading | boolean | false | 否 | 加载状态 | | disabled | boolean | false | 否 | 是否禁用 | | onClick | () void | - | 否 | 点击回调 |组件规范还有一个容易忽略的点不要过早抽象。一个组件只有在一个地方使用的时候没必要强行把它们抽象成公共组件。等它出现在两个及以上页面的时候再抽出来这时候你对它的接口设计才有足够的判断依据。过早抽象出来的组件往往接口设计是错的因为你还不知道真正的变化点在哪里。5. 接口协作与传参规范跟后端对接不扯皮前端开发的大部分联调时间都浪费在“格式不统一、命名不统一、错误处理不统一”的扯皮上。接口规范解决的就是这个问题。5.1 接口文档用什么载体承载现在新项目不建议只靠手写的Word文档或者聊天记录来约定接口了后端要求用OpenAPI 3规范定义接口这是目前最有可行性的做法。OpenAPI 3的核心价值在于三点接口路径、请求参数、响应结构、错误码全部结构化定义。可以自动生成前端请求代码和TypeScript类型定义。前后端共享同一份“契约”后端没按文档实现联调时一眼就能发现。前端这一侧可以用openapi-typescript把后端给的OpenAPI文档转成TypeScript类型npm install -D openapi-typescript npx openapi-typescript https://api.example.com/openapi.json -o ./src/types/api.ts生成的类型文件相当于一份“自动同步的类型契约”后端接口有调整重新跑一次命令就能发现前端哪里需要改。5.2 传参和错误处理的核心约定以下是几条经过实战检验的前后端接口约定可以直接参考分页参数统一格式// 请求 interface PageQuery { page: number // 页码从1开始 size: number // 每页条数 } // 响应 interface PageResultT { list: T[] total: number page: number size: number }这里特别提一个坑分页的页码到底从0开始还是从1开始一定要和后端对齐。有些后端框架默认page从0开始前端传1过去第一页数据就丢了。时间格式统一用ISO 8601字符串。例如2025-01-15T08:30:00Z不要传时间戳也不要用2025/01/15这种和时区、本地化挂钩的格式。前端拿到后用day.js或date-fns处理时区这是一条保底规则。枚举值用字符串而不是数字。比如订单状态与其传1、2、3不如直接传pending、paid、shipped。字符串的语义是自描述的调试工具里看着明白也不容易因为后端在中间插入一个数字导致整条状态链崩掉。错误处理统一走错误码。建议后端返回结构尽量统一{ code: 0, message: success, data: {} }前端封装请求层的时候统一拦截非零code的响应弹全局错误提示。业务代码里只需要处理成功的情况失败分支全部收敛到请求拦截器里。这样既不会漏错误处理也不会让业务代码被一堆冗余的分支塞满。5.3 前端如何约束后端改接口接口规范不只是后端的责任前端也要主动“锁死”契约。我是这么做的接口联调之前先让后端把OpenAPI文档定义好前端基于文档生成类型和请求方法然后跑通一个最简单的接口。后续后端如果改了接口字段需要同步更新OpenAPI文档否则前端类型生成就会报错。这个机制一旦建立起来前后端扯皮的时间能少一半。6. 常见问题与排查技巧实录6.1 规范制定容易执行落地才是真难点带过团队的朋友应该都有同感最难的从来不是“定规范”而是“让规范被执行”。我总结下来推行失败的原因主要有三个第一规范太厚没人看得完。一份一两百页的规范文档任何一个忙得脚不沾地的开发都看不完。规范不是越全越好而是越精越好。先管住几个收益最高的点ESLint、Prettier、commitlint、MR检查其他细节等团队踩了坑再补。第二工具没有接入流水线。任何依赖“人记”的规范都是不可靠的只有把规范嵌入工具链才有生命力。push之前自动lint、提交之前自动检查格式这些都应该在CI/CD流水线里完成而不是等代码merge之后再提醒。第三老代码要不要改。建议是“第一天不强制改”存量代码逐步清理新代码严格执行。可以约定每次改动某个文件的时候顺手把那个文件格式化一遍这样经过一两个迭代周期老代码就会被自然洗白团队也没有抵触情绪。6.2 规范执行中的问题速查表问题现象常见原因解决方案eslint和prettier规则冲突两者对同一规则有不同意见在ESLint配置中继承prettier关闭冲突的格式类规则husky不生效缺少prepare脚本hooks被覆盖package.json中添加prepare: husky installcommitlint提交被拦type不在枚举列表中使用规范的type枚举或用git commit --amend修改信息老项目加ESLint报错几百个存量代码历史包袱太重先以error级别阻止新增问题存量问题通过eslint-disable或批量修复逐步处理组件目录太多找不到公共组件没有统一的组件目录规范约定src/components只放跨页面复用的公共组件业务组件放各自页面目录前后端字段命名不一致没有统一的数据字典通过OpenAPI文档统一后端字段用snake_case或camelCase二选一不要混合6.3 我个人的实操体会项目规范这件事我踩过的坑真不少。最深的体会是规范一定要伴随“工具化”落地且要“分批分阶段”实行不要把战线拉太长。第一步先统一规范工具配置第二步统一Git提交第三步逐步完善组件与接口文档一步一步来不然一次性铺太大团队很容易反弹。另外规范的颗粒度也要把握好。比如“界面统一用设计规范上的颜色不用自定义色值”这种规定是有意义的但“每个方法必须写JSDoc注释”这种就是过度控制它降低的是写代码的效率换来的却往往是“内容重复、没营养”的注释得不偿失。规范永远服务于人不是人为规范服务。最后分享一个实用的小技巧给团队写规范的时候与其直接丢给所有人一份“规范文件”不如在每次代码审查的时候把违反规范的点标注出来并附上规范文档的链接。让规范在真实场景里“被遇到”比让每个人先通读一遍规范要有效得多。前端规范这条路上没有放之四海而皆准的完美方案每个团队都要根据自己的业务阶段和人员构成做取舍但“降低协作成本”这个大方向始终不会变。