前端团队需要的工程规范

1,772 阅读10分钟

前言

在我们平时的开发中,完整的迭代周期需要有需求分析、产品设计、开发、测试、部署、运营阶段。在每一个阶段,我们都必须完成这个阶段的任务,然后进入到下一个阶段。具体到前端,就是如何用规范或者工具等提高我们的开发、测试、部署、运营等阶段的生产效率。

此篇主要聚焦到我们在产品开发阶段的具体规范与工具的落地。

我们研发阶段的规范主要有:

  • 代码规范
  • 项目结构规范
  • Git commit 规范
  • 工作流 workflow 的分支规范

一、代码规范

代码规范的重要性毋庸置疑,在团队到达一定的规模后,更体现其重要性。因为我们的项目大多是由一个团队来完成的,统一的代码风格使得代码可读性大大提高,更重要的是规范的代码可以降低维护成本。

对于前端代码检测工具,独一无二的地位非 ESlint 莫属。哪怕是现在流行的 Typescript 也宣布放弃TSlint, 官方支持了 ESlint。

ESlint 配置

ESlint 被设计为完全可配置,所以你可以关闭每一个规则只运行基本的语法验证,或混合并匹配 ESlint 默认绑定的规则和你的自定义的规则。

但是既然作为团队规范,要么 extend 团队通用的 ESlint 配置,要么 extend ESlint 官方推荐的规则。

比如某司就是 extend 自己公司的 ESlint 配置,如果需要检测 Vue 相关的代码,则在 .eslintrc.js 中配置:

module.exports = {
    extends: [
        '@ecomfe/eslint-config',
        '@ecomfe/eslint-config/vue', // 注意顺序
        // 或者选择严格模式
        // '@ecomfe/eslint-config/vue/strict',
    ],
}

包安装:

npm i -D eslint-plugin-vue

对于自定义一套代码规范,是需要花费很大的人力跟精力去维护与更新。其主要作用就是规范、统一!至于到什么程度或者什么结果,没有一个绝对。所以我们团队直接 extend ESlint 官方推荐的规则。

module.exports = {
    "extends": "eslint:recommended",
}

当然还有 extends 属性值可以是 “eslint:all”,启用当前安装的 ESLint 中所有的核心规则。这些规则可以在 ESLint 的任何版本进行更改, 所以官方是不推荐在产品中使用。

包安装:

npm install eslint --save-dev

前端开发通常是基于 Vue、React 前端框架开发的,所以 Vue 框架,还需要采用 eslint-plugin-vue 相关规则,React 需要采用 eslint-plugin-react 规则。

在我们团队虽然也有 React 项目,但是主要还是以 Vue 项目为主,所以这里着重介绍 Vue 的 ESlint 代码规范。

Vue2 的 .eslintrc.js 配置

module.exports = {
    root: true,
    env: {
       node: true,
       browser: true,
       es6: true
    },
    parser: 'vue-eslint-parser',
    parserOptions: {
        parser: '@babel/eslint-parser',
        sourceType: 'module'
    },
    extends: [
        'eslint:recommended',
        'plugin:vue/strongly-recommended'
    ],
    plugins: [
        'vue'
    ],
    rules: {}
}

包安装:

npm install eslint eslint-plugin-vue --save-dev
npm install @babel/eslint-parser --save-dev

Vue3 的 .eslintrc.js 配置

module.exports = {
  root: true,
  env: {
    node: true,
    browser: true,
    es2021: true
  },
  parser: 'vue-eslint-parser',
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-strongly-recommended'
  ],
  parserOptions: {
    ecmaVersion: 12,
    parser: '@typescript-eslint/parser',
    sourceType: 'module'
  },
  plugins: [
    'vue',
    '@typescript-eslint'
  ],
  rules: {},
  globals: {
    withDefaults: true,
    defineExpose: true,
    defineEmits: true,
    defineProps: true
  }
}

包安装:

npm install eslint eslint-plugin-vue --save-dev
npm install @typescript-eslint/parser --save-dev

Vue2 与 Vue3 的 ESlint 配置最大的区别是对 Typescript 的规范支持,以及 ECMAScript 版本的支持。

Lint-staged 工具,husky 工具

为了保证入库代码都是符合代码规范,我们采用 lint-staged 工具和 husky 工具。lint-staged 能够让 lint 只检测暂存区的文件,所以速度很快。

husky 可以让我们向项目中方便添加 git hooks。

包安装:

npm install husky lint-staged --save-dev

package.json配置

{
    // ...
    "scripts": {
        "lint": "lint-staged",
    },
    "lint-staged": {
        "*.{js,jsx,ts,tsx}": [
                "eslint --fix",
                "git add"
        ]
    },
    // ...
}
npx husky install
npm set-script prepare "husky install”

安装完成后,package.json 会变成:

{
  "scripts": {
    "prepare": "husky install"
  }
}

VSCode 中 ESlint 的配置

在提交代码之前,最好在文件保存的时候,就根据 Vue 项目中 .eslintrc.js 文件设置的规则自动校验,并依据规则修复代码。

首先在 VSCode 中安装 eslint 插件。然后配置 eslint in setting.json。

修改位置:Code -> 首选项 -> 设置 -> 扩展 (ESlint) -> 在 settings.json 中编辑

{
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true,
    },
    "eslint.codeActionsOnSave.mode": "all",
    "eslint.validate": [
        "vue",
        "javascript",
        "javascriptreact",
        "typescript",
        "typescriptreact"
    ],
    "eslint.codeAction.showDocumentation": {
        "enable": true
    },
    "eslint.probe": [
        "javascript",
        "javascriptreact",
        "typescript",
        "typescriptreact",
        "html",
        "vue",
        "markdown"
    ],
    "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[vue]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "eslint.options": {
    
    }
}

二、项目结构规范

项目结构规范包括文件命名、文件目录等。如果项目的文件结构和代码的组织方式一样,团队成员支援其他项目的时候,沟通成本就会大大降低,同时也避免了公共函数与组件重复开发的问题。

在我们的项目中,前期主要是用模版的方式来沉淀我们的项目结构规范,所以团队中沉淀了 Vue2, Vue3的初始化模版。

以 Vue2 模版为例:

image.png

  • docs: 存放各种 md 文档
  • public: 存放公共资源的 public 资源
  • scripts: 工具脚本
  • src: 存放源代码资源
  • node_modules: 自动安装依赖的目录文件

除了这些目录外,还有一些配置文件,.husky, .eslintrc.js, .gitignore, vue.config.js ...

当然最重要的还是 src 文件中的目录结构:

image.png

  • api: 接口
  • assets: 静态资源
  • components: 公共组件
  • config: 公共配置:比如路由配置,菜单配置
  • core: 核心依赖配置
  • layouts: 布局文件
  • store: vuex 状态管理
  • styles: 样式
  • utils:工具函数
  • views:页面
  • main.js: 入口文件
  • permission.js: 权限文件
  • router.js: 路由入口文件

三、Git Commit 规范

我们在提交代码时候,需要写上 commit 信息,概述该提交代码的目的。当线上出现问题的时候,方便排查问题。如果团队遵守一套 commit 规范,还可以用一些脚本文件自动生成变更历史 CHANGELOG。

一个 commit 信息中包括 Header, Body, Footer 三个部分。书写有意义的文字说明,如:

# Header:72个字符以内,用一行描述主要变更内容;包括三个字段:type(必需)、scope(可选)和 subject(必需)。
# * type只允许使用下面的标识:
# ** feat: 新功能(feature)
# ** fix: 修复 bug
# ** docs: 仅仅修改了文档,比如 README, CHANGELOG, CONTRIBUTE 等等
# ** style: 仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑
# ** refactor: 代码重构,没有加新功能或者修复 bug
# ** perf: 优化相关,比如提升性能、体验
# ** test: 测试用例,包括单元测试、集成测试等
# ** chore: 改变构建流程、或者增加依赖库、工具等
# ** revert: 回滚到上一个版本
# ** release: 发布新版本,更新 tag
# // 空一行
# Body:更详细的说明文本。 需要描述的信息包括:
# * 为什么这个变更是必须的? 它可能是用来修复一个bug,增加一个 feature,提升性能、可靠性、稳定性等等
# * 他如何解决这个问题? 具体描述解决问题的步骤
# * 是否存在副作用、风险?
# // 空一行
# Footer:一些备注, 通常是 BREAKING CHANGE 或修复的 bug 的链接

我们还可以借助代码提交规范工具来规范我们的提交信息,如 commitlint 与 husky。

commitlint

npm install @commitlint/cli @commitlint/config-conventional --save-dev

配置 package.json:

{
    "commitlint": {
        "extends": ["@commitlint/config-conventional"],
        "rules": {
            "type-enum":[
                2,
                "always",
                [
                    "feat",
                    "fix",
                    "docs",
                    "style",
                    "refactor",
                    "test",
                    "revert",
                    "chore"
                ]
            ],
            "type-case": [0],
            "type-empty": [0],
            "scope-empty": [0],
            "scope-case": [0],
            "subject-full-stop": [0, "never"],
            "subject-case": [0, "never"],
            "header-max-length": [0, "always", 72]
        }
    }
}

配置 git hooks

npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

四、工作流 workflow 的分支规范

代码分支模式贯穿了开发、集成、发布的整个过程。团队可以根据自身的业务特点或者团队规模来选择合适的代码分支模式。

常见的分支模式,有版本发布模式与持续发布模式。版本发布模式适用于集多种功能到一个版本,并在特定的时间进行新版本的发布。持续发布模式适用于迭代快,按功能 feature 快速迭代的产品。

我们团队大部分产品按照版本发布模式来开发。主要使用以下几种类型的分支:

  • 主分支:保证 master 分支与线上分支一致,设置为受保护分支,不允许直接修改 master 分支,避免在 master 分支上解决合并冲突问题,必须经过团队负责人 review 以后才能合并到 master 分支上。
  • 测试分支:保证 develop 分支只用于线下环境,不允许直接更改代码,只用于测试。禁止将develop 分支合并到 master。
  • 版本里程碑:给稳定版本打 tag,版本格式:v{主版本号}.{次版本号}.{修订号},版本号递增,如:v1.2.3。具体规则如下: 主版本号:做了不兼容的 API 修改,大的版本变动。 次版本号:做了向下兼容的功能性新增,小的版本变动。 修订号:做了向下兼容的问题修正,日常稳定版本修复变动。
  • 版本分支:release-{版本号},如:6.4版本,分支名 release-6.4;开发中的版本分支由版本负责人定期从 master 向 release 分支合并一次,版本发布以后最长保留半年时间。
  • 功能开发分支:feature/{版本号}-{开发人员名字拼音前缀}-{功能},如:开发人员张三,2022年4月27日创建分支,修改团队功能,从对应的 release 分支 check 出个人开发分支:feature/6.4-zs-team;版本发布以后最长保留1个月时间。
  • 紧急修复分支:hotfix/{版本号}-{功能},如:hotfix/6.3.99-app;紧急修复发布以后最长保留1周时间

还有部分项目是持续发布模式,其主要使用以下几种类型的分支:

  • 主分支:master,依然是受保护分支,不可以直接修改,需要负责人 review megre 请求之后合并过来。生产环境是依据 master 去打 tag 包来发版,tag包要求:版本、内容描述等。
  • 灰度分支:gray,灰度环境发版分支,部分项目有灰度分支,也是受保护分支,不可直接修改,需要负责人 review megre 请求之后合并过来。
  • 测试分支:test,测试环境发版分支,也是受保护分支,不可直接修改,需要从个人开发分支自测完了之后 megre 过来。
  • 个人开发分支:以需求或以开发者名字命名,按照需求以上述分支为基础去创建个人开发分支,待需求上线之后,看具体情况及时清理不需要的个人分支。

五、最后

正所谓无规矩不成方圆,好的团队规范可以促进团队合作、降低代码的维护成本,并且有利于code review。

除了上面提到研发阶段的代码规范、项目目录规范、Git Commit规范、代码分支规范,在实际的产品生命周期中还有需求分析、产品设计、测试、部署、运营阶段等阶段的规范。各阶段都需要沉淀出相对最佳的实践,并逐步形成统一规范。比如我们在部署阶段,所有产品都部署到容器平台上,前端静态资源部署到 OSS 文件中。运营阶段产品都接入埋点平台,并生成埋点报表数据;同时也接入前端错误监控,性能监控等。

最后以这些流程为基础,建立整套的团队项目流程管控。

重要参考资料:

  1. eslint.org/
  2. github.com/ecomfe/esli…
  3. eslint.vuejs.org/rules/
  4. github.com/yannickcr/e…