react-native(版本0.77)接入husky分析(用于git提交校验)

78 阅读4分钟
代码提交规范(基于Conventional Commits)
功能目标:
1.统一提交格式(如feat,fix 等)
2.提交前自动lint 格式化(eslint + prettier)
3.防止提交不规范代码(lint-staged)
4.检验提交信息格式(commitlint)
5.自动钩子执行(husky)

最终效果:
git commit -m 'feat(user): 新增用户信息页面'
格式不规范拒绝提交: 
git commit -m 'update stuff' // 会失败

一.安装依赖:
# 安装提交校验相关工具(开发依赖)
pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional

包的功能和作用:

1.husky    git hook工具,让你在git的生命周期事件中运行脚本
    类别: 工具类
    Husky 允许你轻松管理 Git  Hooks(如 pre-commit, pre-push, commit-msg 等),并在这些节点执行脚本或工具。
    1.安装husky
    npm install --save-dev husky
    2.初始化husky(创建.husky/目录)
    npx husky install
    3.添加hook
    npx husky add .husky/pre-commit "npx lint-staged"
    /**
        在husky 文件下添加 pre-commit文件 并且配置上 lint-staged 执行的命令
        这个命令可以来源于package 中配置好的pnpm 命令 
        比如: pre-commit文件 可以存在的命令: pnpm run lint-staged 
    * /
    npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"
    
    
    也可以npx --no-install commitlint --quiet --edit $1
    
    --no-install 不自动安装依赖包
    如果 commitlint 没有安装在 node_modules 中,则命令会立即失败,避免不必要的远程拉包行为。 
    --quiet
    静默模式,只输出错误信息。
    --edit $1
    指定 Git 传入的提交信息文件(如 .git/COMMIT_EDITMSG),commitlint 会读取该文件并进行格式校验。
    $1 是 Git 钩子自动传入的参数,表示提交信息文件的路径。
    /**
        在husky 文件下添加commit-msg文件 并且配置上 lint-staged 执行的命令
        这个命令可以来源于package 中配置好的pnpm 命令 
        比如: pre-commit文件 可以存在的命令: pnpm run lint-staged 
    * /
    
2.lint-staged    代码检查优化工具,只对git暂存区(staged)文件执行 lint/format
    类别:代码质量工具
    lint-staged 会只对已 git add 的文件执行指定的检查或格式化操作,提高效率(不影响整个代码库),避免不必要的更改。
    搭配husky使用,在pre-commit时自动执行检查
    在package.json 中配置:
    {
          "lint-staged": {
            "*.{js,jsx,ts,tsx}": [
              "eslint --fix",     // 对于eslint 执行校验
              "prettier --write"    // 对于prettier 执行的校验
            ],
            "*.json": ["prettier --write"]
          }
        }
    1.git 暂存文件(即你git add 文件)
    2.lint-staged    提取文件列表,逐个执行你配置的命令(如eslint --fix)
    3.修改后自动git add,不会破坏提交流程
    
3.@commitlint/cli    git提交信息校验工具,校验commit message 格式是否符合约定
    类别: 校验工具
    @commitlint/cli  是一个用于校验git提交信息是否符合指定格式的命令工具。它配置git的
    commit-msg hook 使用,防止不规范的commit message 被提交
    列如: 阻止如下格式:
        Update stuff
    推荐格式(convertional commits):
    feat: 添加登录功能
    fix: 修复首页闪退功能bug
    
    常见命令:
    npx commitlint --edit HEAD
    npx commitlint --from=HEAD~1 --to=HEAD

4.@commitlint/config-conventional    commitlint 配置,提供符合conventional commits的校验规则
    类别: 配置插件
    这是commitlint 提供的一个规则预设,包含了符合conventional commits 规范校验规则(类似于ESLint 的
    eslint-config-standard)。
    conventional commits 是一套提交信息的标准,定义了提交类型(如feat, fix, docs, chore, refator)与格式
        提交规范示列:
        feat: 增加注册接口
        fix: 修复 token 失效问题
        docs: 更新接口文档
        chore: 升级依赖
    结合cli配置:
    创建 commitlint.config.js:
    module.exports = {
      extends: ['@commitlint/config-conventional'],
    };

    
    它们是如何协同工作的:
        1.你执行 git commit 
        2.husky 出发pre-commit
        3.lint-staged 检查格式化已暂存的文件
        4.husky 触发commit-msg
        5.commitlint 校验提交信息格式
        6.不符合规则拒绝提交
        
        
二: 初始化husky
npx husky init
    此命令会:
    在项目根目录创建 .husky/ 目录
    自动添加 prepare 脚本到 package.json  
    
三:配置commitlint
创建commitlint.config.js 文件
module.exports = {
  extends: ['@commitlint/config-conventional'],
};

// 或者
 // 自定义插件
const customPlugin = require('./commitlint-custom-plugin.js')
const typeList = {
  feat: '新功能',
  fix: '修复',
  docs: '文档变更',
  style: '代码格式(不影响代码运行的变动)',
  refactor: '重构(既不是增加feature),也不是修复bug',
  pref: '性能优化',
  test: '增加测试',
  chore: '构建过程或辅助工具的变动',
  revert: '回退',
  build: '打包',
}
module.exports = {
  extends: ['@commitlint/config-conventional'],
  /**
   * rules 字段用于定义校验规则,其格式为:
   * 规则的格式为 [level, condition, value]
   * 其中 level 可以是 0(关闭)、1(警告)或 2(错误);
   * condition 可以是 always 或 never;
   * value 是具体的规则值。
   */
  rules: {
    //确保 type 总是小写。
    'type-case': [2, 'always', 'lower-case'],
    // type 类型定义,表示 git 提交的 type 必须在以下类型范围内
    'type-enum': [2, 'always', [...Object.keys(typeList)]],
    // 指定使用插件中的自定义规则
    'custom-rule': [2, 'always', { allowedTypes: typeList }],
    // subject 大小写不做校验
    'subject-case': [0],
  },
  plugins: [customPlugin],
}

// 自定义插件文件:
新建 commitlint-custom-plugin.js 文件
 // 具体配置见下图
四:配置husky钩子
执行以下命令添加 git 提交校验:
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
  
五: 配置lint-staged(可选但推荐)  
在 package.json 中添加:
"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix",
    "prettier --write"
  ]
}
然后添加 pre-commit 钩子:
npx husky add .husky/pre-commit "npx lint-staged"


package 示列(重点) 
{
  "scripts": {
    "lint": "eslint .",
    "prepare": "husky install"
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "devDependencies": {
    "husky": "^9.0.0",
    "lint-staged": "^15.0.0",
    "@commitlint/cli": "^19.0.0",
    "@commitlint/config-conventional": "^19.0.0"
  }
}
 
 
 测试一把:
 git add .
git commit -m "fix(login): 修复登录接口错误"
# ✅ 提交成功

git commit -m "update bug"
# ❌ 报错:不符合格式

自定义插件配置 新建 commitlint-custom-plugin.js 文件

// commitlint-custom-plugin.js
const colors = require('colors');

/**
 * @description 校验类型是否符合定义
 * @param {*} parsed 提交信息集合
 * @param {*} allowedTypes 定义类型集合
 * @returns 返回类型及是否类型正确
 */
const validType = (value, allowedTypes, isType) => {
  return Object.keys(allowedTypes)?.find(item => item === value);
};
// 类型校验失败后,校验头信息
const validHeader = (parsed, allowedTypes, type = '') => {
  // 判断type是否符合规则
  const typeRegex = Object.keys(allowedTypes).join('|');
  const regexString = `^(${typeRegex})(:|:).+`;
  const regex = new RegExp(regexString);
  const match = parsed.header.match(regex);
  if (match) {
    errorSubject(parsed, match[1]);
  } else {
    errorType(parsed, allowedTypes);
  }
};
// 类型错误时,提示
const errorType = (parsed, allowedTypes) => {
  console.error(
    `
` +
      'ERROR: 请规范填写type=>'.bgRed +
      `
` +
      Object.entries(allowedTypes)
        .map(item => `${item[0]}:${item[1]}\n`.white)
        .join('') +
      `
input: ${parsed.raw}
            `.green,
  );
};
// 主体信息错误,提示
const errorSubject = (parsed, type) => {
  console.error(
    `
          
` +
      'ERROR: 请确认'.bgRed +
      `${type.bgYellow}` +
      '类型后有'.bgRed +
      ':+空格'.bgYellow +
      '并添加内容主体信息'.bgRed +
      `
              
input: ${parsed.raw}
            `.green,
  );
};

module.exports = {
  rules: {
    'custom-rule': (parsed, when, value) => {
      const {allowedTypes} = value;
      const type = validType(parsed.type, allowedTypes, 'type');
      // 类型存在
      if (type) {
        if (!parsed.subject) {
          errorSubject(parsed, type);
        }
      } else {
        validHeader(parsed, allowedTypes, type);
      }
      return [2, 'always'];
    },
  },
};