Bootstrap

前端工程化之规范化(ESLint,Prettier,lint-staged,husky,commitlint)基于vite

前言

团队开发的成员越来越多,项目都是由多个人进行开发和维护,每个人的代码书写习惯和风格又不尽相同,commit 的提交log 也是乱七八糟,为以后的开发和维护增添了很多困难,所以规范和约束在多人协作下,就显得尤为重要。

工具说明

ESLint

  • 目的:ESLint 主要用于发现代码中的问题,如潜在的错误、不一致的编码风格、未使用的变量等。

  • 可配置性:ESLint 允许自定义规则,使其可以强制实施特定的编码标准和最佳实践。

Prettier

  • 目的:Prettier 主要用于自动格式化代码,以保持代码风格的一致性。

  • 风格规则:Prettier 有一套默认的风格规则,例如缩进、行宽、引号等,并且这些规则不太可配置。

commitlint

  • 目的:检查提交消息是否符合常规提交格式,用于在每次提交时生成符合规范的commit消息。

lint-staged

  • 目的:用于在 Git 提交时仅对暂存的文件(即将要提交的文件)运行指定的 linting 或格式化任务。它与 husky 配合使用,可以实现更高效的代码检查和格式化。

husky

  • 代码质量检查:在提交代码之前自动运行 lint、测试等,确保代码符合质量标准。

  • 格式化代码:可以在提交时自动格式化代码,以保持代码风格一致。

  • 自定义检查:允许开发者编写自定义脚本,例如检查提交信息格式,确保遵循约定式提交(Conventional Commits)。

话不多说,直接展开我们的项目规范化构建!

  • 初始化eslint

pnpm install eslint -D
npx eslint --init
  • 配置eslintrc.config.js

 {
        settings: {
            react: {
                version: 'detect',
            },
        },
    },
  { languageOptions: { globals: globals.browser } },
"scripts": {
   "lint": "eslint --fix \"./src/**/*.{js,jsx,ts,tsx}\""
}

注意,在vite项目中,它会初始化这个文件,eslint初始化完成后并不会出现 .esintrc 文件,而是在这个文件的languageOptions上新增内容。

OK,到这里,我们可以先来测试一下,写一行未使用的代码,执行 npm run lint格式检查下面代码。

import React from 'react';

const App = () => {const a={};return <div></div>;
};
export default App;

  • 设置忽略文件 .eslintignore

dist/*
node_modules/*
*.json
public
  • 配置 prettier 格式化,重启vscode

npm install prettier -D
  • 在packages.json 中的 script 配置命令

"scripts": {
    "format": "prettier --write \"src/**/*.+(js|ts|jsx|tsx)\"",
}

这时,运行 npm run format 会将我们项目中的文件都格式化一遍,后续如果添加其他格式的文件,可在该命令中添加,例如:.less后缀的文件。

代码结果

import React from 'react';

const App = () => {
    const a = {};
    return <div></div>;
};
export default App;
  • 设置 .prettierignore忽略文件

node_modules/**
dist/**
public/**
doc/**
  • 解决ESLint和Prettier的冲突

  1. 冲突通常发生在两个工具对某些代码风格规则有不同的处理方式。例如,ESLint 可能要求使用单引号,而 Prettier 默认使用双引号。

  2. 当这两个工具同时运行时,它们可能会对代码的同一部分提出不同的修改建议,从而造成冲突。

方法:安装依赖包

npm install eslint-config-prettier eslint-plugin-prettier -D
  1. eslint-config-prettier 基于 prettier 代码风格的 eslint 规则,即eslint使用pretter规则来格式化代码。
  2. eslint-plugin-prettier 禁用所有与格式相关的 eslint 规则,解决 prettier 与 eslint 规则冲突,确保将其放在 extends 队列最后,这样它将覆盖其他配置。
  • 安装初始化husky

// 初始化husky。 
// 1将prepare脚本添加到package 
// 2、根目录创建.husky文件夹,包含pre-commit钩子
npm install husky -D

npx husky-init

这时,项目根目录下会出现.husky文件夹。  

  • 安装并配置lint-staged

npm install lint-staged -D
  • 配置package.json命令

// 设置lint-staged;提交时prettier代码格式化,eslint检查修复
{ 
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": [
      "prettier --write",
      "eslint --fix"
    ],
    "*.{js,json,ts,tsx,css,scss,html}": [
      "prettier --write"
    ]
  },
}
  • 修改.husky/pre-commit文件,使提交时能执行lint-staged钩子

注意!!! ①pre-commit文件必须在.husky下,而不是 _ 中的pre-commit。②npx lint-staged可以是npm run lint-staged,如果过程中出错,建议使用npx lint-staged

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"


npx lint-staged
  • 安装commit-msg

npm install @commitlint/config-conventional @commitlint/cli --save-dev
  • 根目录新建 commitlint.config.js 配置文件

(这里使用的ES规范导出,但要求使用commonJS规范,也可以将文件命名为.cjs解决)

const Configuration = {
    extends: ['@commitlint/config-conventional'],
    rules: {
        // type 类型定义
        'type-enum': [
            2,
            'always',
            [
                'feat', // 新功能 feature
                'fix', // 修复 bug
                'docs', // 文档注释
                'style', // 代码格式(不影响代码运行的变动)
                'refactor', // 重构(既不增加新功能,也不是修复bug)
                'perf', // 性能优化
                'test', // 增加测试
                'chore', // 构建过程或辅助工具的变动
                'revert', // 回退
                'build', // 打包
            ],
        ],
        // subject 大小写不做校验
        // 自动部署的BUILD ROBOT的commit信息大写,以作区别
        'subject-case': [0],
    },
};

export default Configuration;

commit规范参考。例子:git commit -m 'feat: 测试一下'

 

  • 执行以下命令添加commitlint钩子

npx husky add .husky/commit-msg "npm run commitlint"
  • 在package.json中配置

"scripts": {
    "commitlint": "commitlint --config commitlint.config.js -e -V"
}

按上面步骤修改完,我们在提交代码时候,如果随便写一个提交message将会报错,不允许提交。

代码格式如下  

import React from 'react';

const App = () => {const a = {};return <div></div>;
};
export default App;

代码结果

import React from 'react';

const App = () => {
    const a = {};
    return <div></div>;
};
export default App;

而且,如果我们没有把需要规范的地方解决,即便我们按照正确的提交规范,也不会通过。  

自定义代码提交规则

自定义提交规则可以根据团队开发规范来进行额外配置,假设提交规则为:把每个需求的产品文档链接关联到每一个feature,这样后续要是有问题,也方便找到对应的产品文档。

配置如下commitlint.config.js

主要就增加了plugin 和 三个rule 规则

const Configuration = {
    extends: ['@commitlint/config-conventional'],
    rules: {
        // type 类型定义
        'type-enum': [
            2,
            'always',
            [
                'feat', // 新功能、新特性feature
                'fix', // 修复 bug
                'docs', // 文档修改
                'style', // 代码格式(不影响代码运行的变动)
                'refactor', // 代码重构
                'perf', // 优化相关,比如提升性能、体验
                'test', // 测试用例修改
                'chore', // 其他修改, 比如改变构建流程、或者增加依赖库、工具等
                'revert', // 回滚上一个版本
                'build', // 编译相关的修改,例如发布版本、对项目构建或者依赖的改动
            ],
        ],
        // subject 大小写不做校验
        // 自动部署的BUILD ROBOT的commit信息大写,以作区别
        'subject-case': [0],
        'must-add-document-url': [2, 'always'], // 加入自定义规则
        'body-max-line-length': [2, 'always', 200], // body最大内容行数
        'header-max-length': [2, 'always', 200], // header 最大长度
    },
    plugins: [
        {
            rules: {
                'must-add-document-url': ({ type, body }) => {
                    const ALIYUN_DOCUMENT_PREFIX = 'https://devops.aliyun.com';

                    // 排除的类型
                    const excludeTypes = ['chore', 'refactor', 'style', 'test'];
                    if (excludeTypes.includes(type)) {
                        return [true];
                    }

                    return [body && body.includes(ALIYUN_DOCUMENT_PREFIX), `提交的内容中必须包含云效相关文档地址`];
                },
            },
        },
    ],
};

export default Configuration;

测试一下

到这里,我们的规范化已经配置完成了!其中有一些需要注意的点,比如package.json中的脚本:"format": "prettier --write \"src/**/*.+(js|ts|jsx|tsx)\"",当时我配置的时候使用了" ' ' " 双引号套单引号的写法,执行就检测不到!

;