笔者记

我在 B 端的项目落地的前端开发规范经过多年使用已经趋于稳定,这边分享一下团队内部达成共识的前端规范细则,下文中所有内容和链接均经过脱敏。

前言

导语

总结

对的代码可以让计算机正确执行,好的代码可以让所有人愉快且高效地对现有代码进行审查、修改、扩展。

基于此我们总结了一套完整的规则和指引用于在整个前端开发中作为规范遵守,以保证上述共识。

当然守则约束的是底线,相对于各个项目的实际的约束会相对宽松一点。

用词说明

必须/禁止:指 强制规定,在任何支持该规则的环境下都应该使用,老代码应该迁移

应当/建议/如非必要:指 推荐使用,根据使用环境灵活使用,新代码建议对齐标准

一、 开发规范

  • 组件设计遵循低耦合、高内聚1
  • 使用 抽象 而不是复制黏贴代码,非临时2 的相似代码不应多于 18 行,60个连续字符。
  • 编写组件 / 方法时需要 先考虑目的 ,输入与输出分别是什么,过多的参数会丢失抽象,过少的参数会丧失灵活性,抽象需要优先 考虑之后的扩展性 ,抽象前先与团队成员沟通,抽象后及时通知团队成员。
  • 使用最少3 的字符表达最多的含义,并使用类型和清晰的流式代码代替描述性注释,注释只应该用于 描述特殊业务 和作为 复杂流程的概述 。
  • 一般情况下4 不使用 注释代码的形式保留”可能revert的代码”。无用代码5需要在commit之前清理,以减少后续维护负担。
  • 推荐使用 FIXME / TODO / XXX 等备忘注释前缀。

二、代码提交规范

所有 开发者前端及其附属项目,都应当 使用  Tds Config Preset6 检查符合规范的 commit 记录

Git Commit Message

  • 原则上 建议 最小提交粒度符合下面 type 的粒度,如果一个提交内含有多种类型则使用修改范围最广的类型,并 在message中注明可能影响到的其他修改
  • 善用 rebase 移除冗余的commit记录。PR/MR时尽量squash至 1 ~ 2 个commit记录。(基于多分支部署情况下,不适用此条,你应当尽可能的保留 有意义的 修改记录)
  • Commit Types:
type什么时候应该使用
feat新增了一些业务/工具类库代码
fix修复了一些现有的BUG或样式表现不正常
refactor在原有行为不变的情况下改变了代码结构
style修改了代码风格(lint)
chore新增或修改了工程项目文件,不影响原有业务代码
docs新增或修改了说明文档或者补充了一些注释
perf在原有行为和代码结构不变的情况下增强了性能
test新增或修改了测试用例
ci新增或修改了持续集成相关设置
REALEASE/merge仅限 ci 自动生成版本

Examples:

simple template: type(scope?): title \n\n description and other
修复了一些问题                     ❌ Bad 
fix: 修复了xx面板的xx问题          ✅ Good 
fix(tapDB): 修复了xx面板的xx问题   ✅ Better
update: README.md               ❌ Bad 
docs: update README.md          ✅ Good

Code Review

为了保证功能的可靠性,防止意外的疏忽,对于功能提交 应当 使用 MR 的方式并入主分支,并邀请相关人员进行 Code Review。

核心准则

  • 对于项目而言,是否需要 Code Review 由其 Owner 决定,但一旦启用 Code Review 则 应当 保持,对于基础设施则所有的 MR 都 必须 经过 review
  • 对于 Code Review ,不需要对代码业务逻辑做过多的理解,主要对以下几个方面进行 review:
    • commit 信息 应当 概括且简洁明了
    • 代码 必须 符合本则规范
    • 代码编写逻辑 应当 清晰,且能很容易看懂编写思路
    • 复杂流程应有概述性注释,注释 应当 同实际代码功能无偏差,特殊业务逻辑 应当 包含详细解释
    • 在更新功能以后是否有对文档及测试用例进行更新,自动化测试是否正确、且经过良好设计
  • 任何人 对于有疑问的部分可以直接 comment 在 MR 内,由 MR 的 author 对其修复或解释后进行 resolve,含有 unresolved comment 的 MR 禁止 被合并

如何选择审查者

最合适的审查者应该是能彻底了解和审查你所编辑代码的人。他们通常是代码的所有者: 如 OWNERS 文件(monorepo)中的人。

如果是业务代码,你应当尽可能的按照如下顺序寻找审查者:

  • 本项功能的第一作者
  • 最近一次修改本项功能的小伙伴
  • 其他修改过本项功能的小伙伴
  • 本项目的 maintainer
  • 其他项目成员

对于工具库,无论是否是小修改,你 必须至少 添加一位 主要维护作者 作为审查者,除此以外按照上述规则继续执行。

注意事项

  • 代码审查 应当 基于技术事实和数据,否决 个人意见和个人偏好。(但是你可以基于个人偏好给出 建议,对于作者有权利拒绝修改建议)
  • 关于代码风格问题,任何不在 tds-preset-config 、项目规范以及本指南中提及 禁止 的代码风格 应当 被允许。如果 没有 以前的风格,请遵循原作者的风格
    • 如果认为原始风格存在问题的应当前往频道进行讨论,并视情况进行改进
  • 软件设计方面取决于项目本身,不存在绝对的好或者坏。 如果作者可以证明(通过数据或基于可靠的工程原理)该方法拥有等效的质量及维护成本,那么审查者 应当 接受作者的偏好。
  • 如果没有其他适用规则,则 审查者 可以要求 作者与当前代码库中的内容 保持一致只要不恶化 系统的 整体代码健康状况即可。

收到 Code Review 后应当何时进行?

  • 如果你没有处于重点任务的中,那么应该在收到代码审查后尽快开始。
  • 响应代码审查请求所需的最长时间应该 一个工作日(即第二天早上的第一件事)
  • 如果正处于重点任务中,例如编写代码,请不要打断自己进行代码审查,及时与提交者沟通更换审查者。
  • 如果有建议代码可以通过 suggest code 直接展示给提交者

Code Review 礼仪

对于那些正在被审查代码的人,首要条件是保持有足够的礼貌和尊重,除此以外还要确保你的评论是清楚且有帮助的。例如:

  • 【攻击性的反问句】这个组件为什么放到全局下,你难道不知道这种特化的组件不可以放全局么?❌
  • 【一些与代码无关的人身攻击】❌(可以参考祖安语录)
  • 这个组件放到全局下的理由是什么?✅
  • 这个组件放全局并不好,他还不够抽象,并不能迁移给其他系统使用。✅

紧急情况下加速 Code Review

紧急上线应该是一个 修改:

  • 一个重要的发布版本需要包含某个功能(无法回滚发布)
  • 修复产品中严重影响用户的缺陷
  • 修复一个重要的安全漏洞
  • 等等

在这种情况下,允许由有权限的 maintainer 直接审查后合并,此时应当注意代码的 正确性 并在 发布完成后再做一次完整的 review 。

哪些不是紧急情况?

需要明确的是,如下情形 不是 紧急情况:

  • 仅主观希望本周完成,而不是下周(除非有一些无法避免的硬期限,如 deadline)。
  • 为这个功能已经开发了很长一段时间,希望 尽快提交代码。
  • 因为今天是截止日期(非 deadline),所以产品经理说这个代码今天必须合并上线(无论是 rnd stage 还是线上)。
  • 回滚一个造成测试失败或编译错误。

三、 CSS

预处理器

推荐优先使用 LESS,如非必要项目使用的 css 预处理不超过一种

变量

如果可能应当优先使用预处理器支持的变量定义 css variable 后,在项目里面使用 css variable 作为全局变量,以支持动态主题等能力,全局变量的声明 应当 克制。

命名规范(BEM)

推荐使用BEM命名规范(在scoped环境中只要保证不存在 子组件侵染 即可),可以参考 C 端方案,并尽可能和 C 端方案保持一致 的命名方式

代码质量

使用 style-lint 约束样式代码, 参考 tds preset config

UI 规范

优先使用 @taptap/tds-ui-kit 中的组件。

原子类

在为项目添加原子类的时候 应当 注意如下事项:

  1. 请查阅所添加的原子类是否出现在 tailwind 中,如存在类似的类,请保证此原子类用 tailwind 用法一致,且以 ta 开头
  2. 在一个 html 标签上,原子类叠加的数量应当不多于 4 个,如超过 4 个的应当以 css 类 方式编写
  3. 即使使用原子类的情况下,应当提供的结构化 css 类仍然应当添加,但不应当有任何样式设定。
  4. 原子类的制定应当谨慎、克制,当一个常用的 css 结构出现数量较多的情况下方可将其抽象为原子类。
  5. 使用 结构化 css 设定样式的情况下,不应当同时使用原子类。

四、 Vue

项目需要考虑未来对 Vue2 升级到 Vue3 且在 vue3 中持续维护的可能,所以我们对 vue2 项目的要求会和 vue3 的要求类似,以尽可能的减少迁移成本

  • 如非必要,视图组件 建议 使用SFC(Single File Component)进行编写7,且 必须 使用 Composition-API 风格。
    • 除既有代码以外,新代码 禁止 使用 如下编程范式
      • Class Component
      • Option API (如 defineComponent 中的 data、生命周期定义、computed、methods、mixin 等)
    • 如可以使用 script setup 方式编写代码的,建议 切换。
  • 视图组件之外的代码 必须 全部使用 .ts 代替 .js ,视图组件逐步迁移到 ts/lang="ts",在 ts 语境下 减少使用 any/object 等通用类型以及 //@ts-ignore 等禁用检查指令。
  • 所有 Composition API 必须使用 typescript 编写,且 必须 保证出入参数、返回值、声明正确。
  • 禁止 基于 prototype 扩展 Vue。
  • 对于新启用的 vue 组件库/工具库至少 应当 使用 composition-api 为基准编写,如有可能, 应当 使用 vue-demi 以提供 vue3 支持能力。
  • 如果可能,应当 使用 props 回调代替 emit 以提供 更好的类型声明获取返回值,命名上 禁止 使用 on 开头,应当 使用 handle 开头8
  • 对于 scoped css, 应当仅使用 import (reference)
  • 在组件封装上 应当 尽可能满足以下原则:
    • 在 渲染组件 有可能不依赖上下文(context,vm)、全局实例(service、store、router、i18n)的情况下,应当 尽可能使用 props 获取此类数据,且应当保证无副作用
    • 对于有 全局副作用 行为的 业务组件 应当 尽可能将副作用行为 通过 事件context 方式传递到能处理该行为的 顶层 业务组件上处理
    • 当需要引入(import)任意一个其他业务或兄弟业务模块的组件时,应当 重构目标组件,提升目标组件至双方业务模块的 共有最低父级,并 剔除其全局、局部副作用 行为后方可使用

五、 项目结构与命名规则

  • 组件文件 使用 PascalCase ,name 必须 与组件名 完全相同其他非组件文件 使用 camelCase
  • template 中始终使用 PascalCase ,在 template 中无子项元素推荐使用自闭合标签( <CustomComponent /> )。
  • JS变量使用 camelCase,样式变量/类名使用 kekab-case,如需与后端交互的情况,将映射规则写在 API层(或使用传参进行隐式映射),有助于业务与接口解耦。
  • 在大范围scope中 应当减少出现 或 没有 无意义的变量名,变量名尽量满足自注释。
// 推荐变量范式:isXxx (Boolean)/ xxxStr(String) 
let c = 0  // `❌ Bad` 
let isAdmin = false // `✅` `Good`
  • 组件尽量放在使用组件间最小父级上,越外层要求耦合度越低。

六、 环境变量

参考:  Vue-cli 环境变量和模式

  • 项目的环境存放在 .env.env.[mode] 中,可通过 process.env.[field] 获取
  • 如果需要在本地配置变量,请使用 .env.[mode].local 来进行覆盖,该配置会被 git 忽略(需要在 .gitignore 中配置 .env.local .env.*.local )。
  • 项目配置 不应当 存在秘钥等敏感信息的
    • 前端项目 构建 必须使用 ci 环境变量方式引入
    • 存在后端项目的,应当使用 apollo 方式获取

七、 独立包开发

项目中存在的 公共的 、 独立的、无业务逻辑的 可以公共使用的包应当使用 npm 包的方式安装。 对于 lib 包,应当(视项目而定)在项目对应的 .npmrc 中添加如下内容:

registry=-
@taptap:registry=-
  • 必须 提供 ESM 格式的输出,针对使用环境可以考虑提供 CJS / UMD(min) 等格式
  • 必须 包含 sourcemap,应当使用 typescript 编写,且输出声明文件,如无法自动生成声明的文件的,建议 可以手动编写 部分声明。
  • 对于 复杂包依赖管理的 或者 需要 mono 结构维护的,推荐使用 changeset 进行管理
  • 独立包的依赖 应当 尽可能少
  • 当需要对独立包新增/修改功能时,应当 联系该包 第一作者 或 当前主要维护者,并使用 issue 方式 或 slack 讨论方式新增,修改后的 MR/PR 应至少获得 该文件/模块 第一作者 或 当前主要维护者 approve 后方可合并。
  • 对于基础库,新功能或重要修改 应当 使用 RFC 方式维护包的主要功能。

八、 项目的文档(README.md & docs)

我们认为一个好的 README 应当可以让一个从未接触过项目的人可以快速上手,理解我们的项目是如何运作的,维护的,以及如何在项目的约束下开发代码。

所以我们要求所有的项目如果 时间允许 必须 存在完整的 README,对于 README 要求 至少需要 包含如下内容:

  1. 项目的介绍,至少应当包含:项目的用途,解决的问题
  2. 项目的安装方式,应当包含:如何安装,异常情况的处理(如需要)
  3. 项目的使用方式,应当包含:如何使用,样例代码(独立包要求)
  4. 项目的使用逻辑和思想等,应当包含:如有复杂逻辑的应当包含流程图,如有复杂时序的,如授权 SDK 等应当包含时序图解释
  5. README 的总长度不应当超过 3屏,如果超过,则应当将对应的内容放置到 ./docs 并在 README 中索引内容

并且,额外的可以包含如下可选内容:

  1. 项目独有的规范:如格式等
  2. 项目开发维护的相关文档
  3. 补充资料

对于 README 我们要求对 README 进行定期的修缮,如果修改了任何内容,且涉及文档的 应当同步更新,但迫于时间压力允许滞后,但应当打上标记以后续更迭。

九、 第三方包

  • 对于相对可信任的第三方维护代码,可以选择使用 npm 直接安装的方式,注意 应当 通过 nexus 安装。
  • 对于下载量较低,或使用人数较少的包,应当 clone 一份且固定版本使用,随后定期 更新 & 审阅 该第三方包代码。对于代码量非常大的,且使用某不明二进制包的,建议更换此实现
  • 优先使用 MIT / CC BY 4.0 或 类 MIT 衍生的协议,此类包无协议风险
  • 如非必要,禁止使用 LGPL 、GPL、Mozilla 协议的第三方包,此类协议的开源代码存在传染性协议内容,有法律风险。

十、 协同编程

  • 对于多人维护的项目,应采用 MR 的方式进行合并代码,禁止直接推送代码至共同协作的分支( main / master / develop 等)
  • 主干分支 ( main / master ) 禁止进行历史变更 (rebase / drop)
  • 新的修改合进主分支前 应当 经过自动测试(UT/E2E)与代码审核
  • 多人维护项目应当创建功能分支并统一推送到目标分支,在功能分支合并至 主干分支应当 进行 commit 整理(rebase or squash),并剔除无关内容。

十一 、其他

对象存储

对于项目中使用对象存储的情况下,需要注意存储的对象是否是敏感信息,如存在敏感信息的 必须 使用 私有读 的 bucket 进行管理。

敏感信息的对象(下文信息可能以文件、图片、视频等方式存在)包括但不限于如下内容:

一、低敏感

  • 企业敏感信息:统一社会信用代码、组织机构代码、营业执照号码
  • 个人敏感信息:SSN、未校验的身份证号
  • 位置敏感信息:城市(中国内地)、省份(中国内地)

二、中敏感

  • 企业敏感信息:税务登记证号码
  • 个人敏感信息:车辆识别代码、宗教、姓名(英文)、姓名(简体中文)、姓名(繁体中文)、军官证、电话号码(中国内地)、车牌号(中国内地)
  • 密钥敏感信息:密码、AccessKeyId
  • 设备敏感信息:URL链接、MEID、IMEI、IPv6地址、JDBC连接串、MAC地址、IP地址
  • 位置敏感信息:详细居住地址(中国内地)

三、高敏感

  • 个人敏感信息:电话号码(美国)、信用卡、身份证(新加坡)、身份证(马来西亚)、身份证(中国香港)、港澳通行证、护照号(中国内地)、个人邮箱、手机号(中国内地)、银行卡、身份证(中国内地)
  • 密钥敏感信息:PEM证书、KEY私钥、AccessKey Secret
  • 位置敏感信息:GPS位置
  • 设备敏感信息:Linux-Passwd文件、Linux-Shadow文件
  • 敏感图片信息:身份证图片(中国内地)、护照图片(中国内地)

对于数据敏感性极高的场合(如上文高敏感信息的)应当在 私有读写 的之外,再额外选择使用 数据加密 ,如后端或产品未能预见的情况下,应当主动提醒。

注意: 前端本身的静态文件应当与后端使用的 bucket 隔离,且前端本身的静态文件应确保是非敏感的

脚注

  1. 概念参考:什么是高内聚与低耦合

  2. 如果代码仅存在于当前版本或用于测试,则需要注明 // FIXME 临时代码

  3. 强调代码的高效可读性,如非必要禁止使用 ~~ 代替 Math.floor() 等奇技淫巧。

  4. 一些修改需要于当前代码进行对照参考,此时需要添加对应注释。

  5. 函数声明 / 变量声明 / 注释 / console.log 等。

  6. 指内部的一个通用的 config 工具包,包含 eslint、prettier、commitlint 等配置

  7. 本条已经更新为使用 vue.FC 参考 vue函数签名

  8. 在 2024年这个情况已经有所改善了,但目前并未有计划更新规则

本文标题:谈谈我们 taptap B端的前端规范

永久链接:https://iceprosurface.com/code/front-end/rules/

作者授权:本文由 icepro 原创编译并授权刊载发布。

版权声明:本文使用「署名-非商业性使用-相同方式共享 4.0 国际」创作共享协议,转载或使用请遵守署名协议。

查看源码: