前端项目代码提交规范

3,308 阅读3分钟

制定前端代码提交规范,能更方便的维护我们的项目代码,尤其是多人开发时格外重要。下面介绍下使用 commitlint+eslint+prettier 规范化代码提交。

插件简介

项目中用到的插件包括:husky, lint-staged, eslint, prettier, commitlint。

1. husky

在 git 中,每次执行 git commit, git push 等操作时,会触发一个或多个 shell 脚本,这些脚本称为钩子,存放在 .git/hooks 目录下。钩子分为前置钩子和后置钩子,前置钩子为 git 命令调用前执行,后置钩子为 git 命令完成后执行。

所以在 git 命令提交时,我们可以额外做一些事情,比如提交前的代码检测,提交后的部署等功能。husky 插件可以在 git 执行特定事件时触发运行特定脚本,支持 git 所有的钩子。这里利用 husky 插件来实现代码提交前的代码格式化,代码检测,commit 信息校验等功能。

4.x以上

包安装:

cnpm i husky --save-dev

packages.json 添加配置:

"scripts": {
    "prepare": "husky install" // 包安装完成后,激活生成钩子脚本,包安装后自动执行
},
npm run prepare

添加自定义钩子:

npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg "npx --no -- commitlint --edit ${1}\"

添加完成后,根目录下会生成 .husky 文件夹,将钩子文件推到远端仓库。以后每次代码推送,都会执行钩子文件中定义的命令。

image.png

2. lint-staged

lint-staged 插件代表只处理 git 暂存区的文件,这样仅会修改到自己提交的文件,不会影响项目其他未提交的文件,控制代码修改风险,同时也提高处理性能。

包安装:

cnpm i lint-staged --save-dev

packages.json 添加配置:

"lint-staged": {
    "*.{js,jsx,ts,tsx,vue,md,html,css}": [
        "eslint --fix --quiet"
    ]
}

或者在根目录下新建 .lintstagedrc 文件,添加配置:

{
  "*.{js,jsx,ts,tsx,vue}": [
    "eslint --fix --quiet"
  ]
}

通过 husky 钩子执行 lint-staged。

npx husky add .husky/pre-commit "npx lint-staged"

3. eslint

ESLint 是一款插件化的 JavaScript 代码静态检查工具,其核心是通过对代码解析得到的 AST(Abstract Syntax Tree,抽象语法树)进行模式匹配,来分析代码达到检查代码质量和风格问题的能力。

包安装:

cnpm i eslint eslint-config-airbnb-base eslint-config-prettier eslint-plugin-import eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/eslint-plugin @typescript-eslint/parser --save-dev

根目录下新增 .eslintrc.js 文件:

// .eslintrc.js

module.exports = {
    root: true,
    env: {
        browser: true,
        es6: true,
        node: true,
        'vue/setup-compiler-macros': true,
    },
    globals: {
        wx: false,
        AMap: true,
        AMapUI: true,
    },
    extends: [
        'airbnb-base',
        'plugin:vue/essential',
        'plugin:prettier/recommended',
    ],
    parserOptions: {
        ecmaVersion: 12,
        parser: '@typescript-eslint/parser',
        sourceType: 'module',
    },
    plugins: ['vue', '@typescript-eslint'],
    settings: {},
    rules: {
        'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', // 禁止console
        'no-unused-expressions': [
            'error',
            {
                    allowShortCircuit: true, // 允许短路逻辑
                    allowTernary: true, // 允许三目运算
            },
        ],
        'import/prefer-default-export': 'off', // 如果只有一个值,要用 default 导出
        'import/no-unresolved': 'off', // import识别路径,因为alias设置
        'import/extensions': 'off', // 扩展简写
        'no-param-reassign': 'off', // 函数参数修改
        'no-plusplus': 'off', // 一元操作符
        'no-nested-ternary': 'off', // 禁用嵌套的三元表达式
        'no-bitwise': 'off', // 禁用按位运算符
        'no-multi-assign': 'off', // 禁止连续赋值
        'no-unsafe-optional-chaining': 'warn', // 不安全的可选链
        'no-restricted-globals': 'off', // 指定不希望在应用程序中使用的全局变量名称
        'no-underscore-dangle': 'off', // 不允许在标识符中使用悬空下划线
        'no-use-before-define': 'warn', // 在遇到对尚未声明的标识符的引用时发出警告
        'no-empty': ['error', { allowEmptyCatch: true }], // 不允许空块语句, allowEmptyCatch: true允许空catch子句
        'consistent-return': 'off', // return语句总是或永远不指定值
        'no-case-declarations': 'off', // 防止访问未初始化的词汇绑定以及跨越事例子句访问提升
        'no-async-promise-executor': 'off', // promise是否是异步函数
        'default-param-last': 'warn', // 带默认值的参数放最后面
        'prefer-destructuring': ['error', { object: true, array: false }], // 是否优先使用数组和对象解构
        eqeqeq: 'warn', // 消除类型不安全的等式操作符
        'vue/no-v-model-argument': 'off', // v-model 带参数
        'vue/no-multiple-template-root': 'off', // 根元素只有一个
        'vue/multi-word-component-names': 'off', // 组件名称是否是多字母
        'vue/no-mutating-props': 'warn',
        'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
    },
}

根目录下新增 .eslintignore 文件:( eslint 校验忽略目录)

.DS_Store
.history
.husky
dist
node_modules
*.local
yarn-error.log
yarn.lock
tests
types
types.ts

代码执行 eslint :

eslint --fix --quiet . --ext .js,.ts,.vue

eslint 核心配置项解析:

  • parser 解析器:ESLint 默认使用 Espreer 作为其解析器,但是该解析器仅支持最新的 ECMPScript(es5) 标准,对于实验性的语法和非标准(例如 Flow 或 TypeScript 类型)语法是不支持的。因此,开源社区提供了两种解析器:babel-eslint@typescript-eslint/parser
  • parserOptions 解析器选项
  • env 和 global 环境和全局变量:代码中未声明的变量可能是库中定义的,需要在此设置中声明。值有三个:writable 可重写,readonly 只读和 off 禁用。
  • rules 规则www.verydoc.net/eslint/0000…
  • plugins 插件:自定义插件来检查代码语法。比如 ts 开发需要将解析器修改为 @typescript-eslint/parser,同时安装 @typescript-eslint/eslint-plugin 插件来拓展规则。
  • extends扩展:继承已有的配置文件,值为字符串或数组。

4. prettier

prettier 是一个纯粹的代码格式化工具。eslint 主要做代码检查,代码格式化有限,所以与 prettier 搭配使用。用 eslint 进行代码校验,用 prettier 统一代码风格。

包安装:

cnpm i prettier --save-dev

根目录下新增 .prettierrc.js 文件:

// .prettierrc.js

module.exports = {
    // extends: ["airbnb", "prettier"],
    // 一行最多 80 字符
    printWidth: 80,
    // 使用 2 个空格缩进
    tabWidth: 2,
    // 是否使用tab进行缩进
    useTabs: true,
    // 行尾不需要有分号
    semi: false,
    // 使用单引号
    singleQuote: true,
    // 对象的 key 仅在必要时用引号
    quoteProps: 'as-needed',
    // jsx 不使用单引号,而使用双引号
    jsxSingleQuote: false,
    // 是否使用尾逗号,有三个可选值"<none|es5|all>"
    trailingComma: 'es5',
    // 大括号内的首尾需要空格
    bracketSpacing: true,
    // jsx 标签的反尖括号需要换行
    jsxBracketSameLine: false,
    // 箭头函数,如果只有一个参数则省略括号
    arrowParens: 'avoid',
    // 使用默认的折行标准
    proseWrap: 'preserve',
    // 标签折行
    htmlWhitespaceSensitivity: 'ignore',
    // 换行符使用 lf
    endOfLine: 'lf',
    // 文件后缀名对应的格式化处理器
    // parsers: {
    //   ".jsx": "flow",
    //   ".scss": "scss",
    //   ".less": "css",
    //   ".vue": "vue",
    //   ".ux": "vue",
    //   ".yml": "yaml",
    //   ".foo": "flow",
    // },
}

根目录下新增 .prettierignore 文件:(格式化忽略的目录)

.DS_Store
.history
.husky
dist
node_modules
*.local
yarn-error.log
yarn.lock

代码执行 prettier 命令:

prettier --write .

prettier 与 eslint 配合使用

安装包:

  • eslint-config-prettier 的作用是关掉和 prettier 冲突的 eslint 配置。
  • eslint-plugin-prettier 的作用时是将 prettier 的能力集成到 eslint 中。
cnpm i eslint-config-prettier eslint-plugin-prettier --save-dev

.eslintrc.js 文件配置:

{
 "extends": [
     "plugin:prettier/recommended" // 放最后面,避免被覆盖
 ]
}

5. commitlint

commitlint 是一个命令行工具,对 git commit 的信息做验证。

安装包:

cnpm i @commitlint/cli @commitlint/config-conventional 

根目录下新建 commitlint.config.js 文件:

// commitlint.config.js

module.exports = {
    extends: ['@commitlint/config-conventional'], // 继承官方提供的规则
}

husky 添加钩子使用 commitlint:

npx husky add .husky/commit-msg \"npx --no -- commitlint --edit ${1}\"

npx --no :表示只使用本地项目 node_modules 的脚本,找不到的时候不会自动下载。

commitlint --edit <文件名>:执行 commitlint 命令行工具,并使用 --edit 选项,从一个文件里提取 commit 内容进行校验。校验规则由 commitlint.config.js 配置文件来指定。在 commit-msg 脚本中,通过 $1 拿到提交信息。$1 指向的是 .git/COMMIT_EDITMSG 文件,该文件保存着最后一次提交的 commit 信息。

vscode 插件支持

vscode 开发时,安装对应插件,可以实现代码保存的时候自动提示或修复。

1. 插件安装

vscode 扩展里安装 eslint 插件, prettier 插件,EditorConfig for VS Code 插件。

image.png

image.png

EditorConfig for VS Code 插件可以让编译器读取配置文件,并且按照配置文件 .editorconfig 里面的规定来格式化代码。

image.png

2. 设置修改

VSCode 的 setting.json 设置分为用户区和工作区两个级别,其中用户区会对所有项目生效,而工作区只对当前项目生效。

用户区

修改设置项有以下两种方式:

方式一:

image.png

打开的 settings.json 文件添加如下代码:

"editor.formatOnSave": true, // 保存的时候格式化
"editor.codeActionsOnSave": { 
    "source.fixAll.eslint": true
}

方式二:

通过 vscode 设置界面来操作。

image.png

工作区

根目录下创建 .vscode/settings.json 文件, 并添加如下代码:

{
  "editor.formatOnSave": true, // 保存的时候格式化
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
  }
}

image.png

一般建议使用用户区级别的设置,针对所有项目生效,统一配置。

3. .editorconfig 设置

根目录下新增 .editorconfig 文件,定义编辑器的代码规范规则,该规则高于编译器默认的代码规范规则。该配置项提供给 EditorConfig for VS Code 插件使用。

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
indent_size = 2

项目实践

1. 安装包

cnpm i @commitlint/cli @commitlint/config-conventional @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-airbnb-base eslint-config-prettier eslint-plugin-import eslint-plugin-prettier eslint-plugin-vue husky lint-staged prettier --save-dev

2. 修改 packages.json

增加 lint-staged 设置项:

{
    ...
    "scripts": {
        "prepare": "husky install",
        "huskyInit": "npx husky add .husky/pre-commit \"npx lint-staged --allow-empty\" && npx husky add .husky/commit-msg \"npx --no -- commitlint --edit ${1}\"",
        "prettier": "prettier --write .",
        "lint": "eslint --fix --quiet . --ext .js,.ts,.vue"
    },
    "devDependencies": {
        "@commitlint/cli": "^17.4.2",
        "@commitlint/config-conventional": "^17.4.2",
        "@typescript-eslint/eslint-plugin": "^5.20.0",
        "@typescript-eslint/parser": "^5.20.0",
        "eslint": "^8.14.0",
        "eslint-config-airbnb-base": "^15.0.0",
        "eslint-config-prettier": "^8.5.0",
        "eslint-plugin-import": "^2.26.0",
        "eslint-plugin-prettier": "^4.0.0",
        "eslint-plugin-vue": "^8.7.1",
        "husky": "^7.0.4",
        "lint-staged": "^13.1.0",
        "prettier": "^2.6.2",
        ...
    },
    "lint-staged": {
        "*.{js,jsx,ts,tsx,vue,md,html,css}": [
                "eslint --fix --quiet"
        ]
    }
}

执行以下命令初始化 husky,并生成钩子文件:

npm run prepare
npm run huskyInit

3. 添加配置文件

  • .editorconfig
  • .eslintrc.js
  • .eslintignore
  • .prettierignore
  • .prettierrc.js
  • commitlint.config.js

4. 总结

当git commit的时候,执行钩子逻辑,pre-commit 钩子对暂存区的文件执行 eslint 校验,以及 prettier 格式化;当校验通过,且代码格式化完成后执行 commit-msg 钩子逻辑,对 git commit 的提交信息做格式验证,验证通过后 commit 成功。

参考文件

www.cnblogs.com/Yellow-ice/…

blog.csdn.net/fe_watermel…

mp.weixin.qq.com/s/OlMMNAYHq…