前端工程化之 commitlint + husky 实现 git 提交规范化 编写规范提示

安装 husky 和 lint-staged

 husky  可以用于实现各种 git Hook。这里主要用到 pre-commit 这个 hook,在执行 commit 之前,运行一些自定义操作

 lint-staged  用于对 git 暂存区中的文件执行代码检测

npm i husky lint-staged -D

Prettier 配置

根目录下创建 .prettierrc.js 文件

module.exports = {
  // 一行最多 100 字符
  printWidth: 100,
  // 不使用缩进符,而使用空格
  useTabs: false,
  // 使用 2 个空格缩进
  tabWidth: 2,
  tabSize: 2,
  // 行尾需要有分号
  semi: true,
  // 使用单引号
  singleQuote: true,
  // jsx 不使用单引号,而使用双引号
  jsxSingleQuote: false,
  // 末尾不需要逗号 'es5'  none
  trailingComma: 'es5',
  // 大括号内的首尾需要空格
  bracketSpacing: true,
  // jsx 标签的反尖括号需要换行
  jsxBracketSameLine: false,
  // 在单个箭头函数参数周围加上括号<avoid|always>
  arrowParens: 'avoid',
  // 不需要写文件开头的 @prettier
  requirePragma: false,
  // 不需要自动在文件开头插入 @prettier
  insertPragma: false,
  // 使用默认的折行标准
  proseWrap: 'preserve',
  // 换行符使用 lf 结尾是 \n \r \n\r auto
  endOfLine: 'lf',
  vueIndentScriptAndStyle: true,
};

 配置好 Pretteir 文件后 可直接使用 commitizen init cz-conventional-changelog -D --save-exact  指令在package,json 文件中生成命令

 

 

Eslint 配置

 npm i eslint-plugin-react eslint-plugin-react-native -D
npm i eslint eslint-plugin-html eslint-plugin-vue babel-eslint -D

根目录下创建 .eslintrc.js 文件

module.exports = {
  root: true,
  // parser: 'babel-eslint',
  env: {
    node: true,
  },
  // extends: ["plugin:vue/base", "plugin:vue/recommended"],
  extends: ['plugin:vue/base'],
  parserOptions: {
    parser: 'babel-eslint',
  },
  plugins: ['html', 'vue'],
  rules: {
    /*
    "off"或者0    //关闭规则关闭
    "warn"或者1    //在打开的规则作为警告(不影响退出代码)
    "error"或者2    //把规则作为一个错误(退出代码触发时为1) 
    */

    'no-var': 'error', // 禁止使用var
    'prefer-const': 'error', // 建议使用const
    'no-const-assign': 'error', // 禁止修改使用const(no-const-assign)声明的变量
    'object-shorthand': 'error', // 方法属性值简写
    'quote-props': ['error', 'as-needed'], // 只对那些无效的标示使用引号 ''
    'no-array-constructor': 'error', // 数组要求字面量赋值
    'no-new-object': 'error', // 对象使用字面值创建对象
    'array-callback-return': 'error', // 在数组方法的回调中强制执行
    'prefer-destructuring': [
      'error',
      {
        array: true,
        object: true,
      },
      {
        enforceForRenamedProperties: false,
      },
    ], // 用对象的解构赋值来获取和使用对象某个或多个属性值
    quotes: ['error', 'single'], // string 统一用单引号 ''
    'prefer-template': 'error', // 建议使用模板字符串
    'no-eval': 'error', // 禁止使用eval
    'no-useless-escape': 'error', // 不要使用不必要的转义字符
    'func-style': 'error', // 用命名函数表达式而不是函数声明 const func=()=>{}
    'prefer-rest-params': 'error', // 建议使用rest参数而不是参数
    'space-before-function-paren': ['error', 'never'], // 函数前不允许使用空格或
    'space-before-blocks': ['error', 'always'], // 块前需要空格
    'no-param-reassign': 'error', // 不允许重新分配函数参数
    'prefer-spread': 'error', // 建议使用spread语法而不是.apply()
    'prefer-arrow-callback': 'error', // 建议使用箭头函数
    'arrow-spacing': 'error', // 箭头函数的箭头前后需要空格
    //  "arrow-parens": ["error", "always"], // 在arrow函数参数中需要paren
    'arrow-body-style': ['error', 'always'], // 在箭头函数体中需要大括号
    'no-confusing-arrow': ['error', { allowParens: true }], // 不允许箭头函数与比较混淆
    'no-useless-constructor': 'error', // 不允许不必要的构造函数
    'no-dupe-class-members': 'error', // 不允许在类成员中使用重复名称
    'no-duplicate-imports': ['error', { includeExports: true }], // 不允许重复导入
    //  "import/no-mutable-exports": "error", // 不要导出可变的绑定
    //  "import/prefer-default-export": "error", // 在只有一个导出的模块里,用 export default 更好
    //  "import/first": "error", // import 放在其他所有语句之前
    'dot-notation': 'error', // 访问属性时使用点符号
    'no-restricted-properties': 'error', // 做幂运算时用幂操作符 **
    'one-var': ['off', 'always'], // 强制在函数中单独声明变量
    'no-multi-assign': 'error', // 不要使用连续变量分配
    'no-plusplus': 'error', // 不要使用一元递增递减运算符(++, --)
    'no-unused-vars': 'off', // 不允许有未使用的变量
    eqeqeq: ['error', 'always'], // 使用 === 和 !== 而不是 == 和 !=
    'no-case-declarations': 'error', // 不允许在case/default子句中使用词法声明
    'no-nested-ternary': 'error', // 三元表达式不应该嵌套,通常是单行表达式
    'no-unneeded-ternary': 'error', // 避免不需要的三元表达式
    'no-mixed-operators': 'error', // 不允许不同运算符的混合
    'nonblock-statement-body-position': ['error', 'beside'], // 强制单行语句的位置
    'brace-style': 'error', // 需要大括号样式
    'no-else-return': 'error', // 如果if语句都要用return返回,那后面的else就不用写了。如果if块中包含return,它后面的else if块中也包含了return,这个时候就可以把else if拆开
    'spaced-comment': [
      'error',
      'always',
      {
        line: {
          markers: ['/'],
          exceptions: ['-', '+'],
        },
        block: {
          markers: ['!'],
          exceptions: ['*'],
          balanced: true,
        },
      },
    ],
    //  "indent": ["error", 2, { "SwitchCase": 1}], // 强制2个空格
    'keyword-spacing': ['error', { before: true }], // 在关键字前后强制使用一致的间距
    'space-infix-ops': ['error', { int32Hint: false }], // 用空格来隔开运算符
    'padded-blocks': ['error', 'never'], // 不要故意留一些没必要的空白行
    'array-bracket-spacing': ['error', 'never'], // 方括号里不要加空格
    'object-curly-spacing': ['error', 'always'], // 花括号 {} 里加空格
    'comma-spacing': ['error', { before: false, after: true }], //  , 前避免空格, , 后需要空格
    'key-spacing': ['error', { beforeColon: false }], // 在对象的属性中, 键值之间要有空格
    'no-trailing-spaces': 'error', // 行末不要空格
    'no-multiple-empty-lines': 'error', // 避免出现多个空行。 在文件末尾只允许空一行
    'no-new-wrappers': 'error', // 不允许基元包装实例
    radix: ['error', 'as-needed'], // 需要基数参数
    //  "id-length": "error",
    camelcase: ['error', { properties: 'always' }], // 要求驼峰式命名对象、函数、实例
    'new-cap': 'off', // 要求构造函数名称以大写字母开头
    'no-underscore-dangle': 'error', // 不要用前置或后置下划线
  },
  // 可以忽略代码中的 window $这些
    globals: {
      initGeetest: true,
      window: true,
     },

};

 

Stylelint 配置

stylelint-config-standard 是 stylelint 的推荐配置

stylelint-order css 属性排序插件(先写定位,再写盒模型,再写内容区样式,最后写 CSS3 相关属性)

stylelint-config-recess-order stylelint-order 插件的第三方配置

npm i stylelint stylelint-config-standard stylelint-order stylelint-config-recess-order -D

根目录新建一个 .stylelintrc.js 文件、

module.exports = {
  processors: [],
  plugins: [],
  extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],
  rules: {
    // 不需要

    'space-before-function-paren': 0, // 函数定义时括号前面要不要有空格

    'eol-last': 0, // 文件以单一的换行符结束

    'no-extra-semi': 0, // 可以多余的冒号

    semi: 0, // 语句可以不需要分号结尾

    eqeqeq: 0, // 必须使用全等

    'one-var': 0, // 连续声明

    'no-undef': 0, // 可以 有未定义的变量

    // 警告

    'no-extra-boolean-cast': 1, // 不必要的bool转换

    'no-extra-parens': 1, // 非必要的括号

    'no-empty': 1, // 块语句中的内容不能为空

    'no-use-before-define': [1, 'nofunc'], // 未定义前不能使用

    complexity: [1, 10], // 循环复杂度

    'no-unused-vars': 1, // 不能有声明后未被使用的变量或参数

    // vue

    'flow-vars/define-flow-type': 1,

    'flow-vars/use-flow-type': 1,

    // react

    'react/jsx-uses-react': 2,

    'react/jsx-uses-vars': 2,

    // 错误

    'comma-dangle': [2, 'never'], // 对象字面量项尾不能有逗号

    'no-debugger': 2, // 禁止使用debugger

    'no-constant-condition': 2, // 禁止在条件中使用常量表达式 if(true) if(1)

    'no-dupe-args': 2, // 函数参数不能重复

    'no-dupe-keys': 2, // 在创建对象字面量时不允许键重复 {a:1,a:1}

    'no-duplicate-case': 2, // switch中的case标签不能重复

    'no-empty-character-class': 2, // 正则表达式中的[]内容不能为空

    'no-invalid-regexp': 2, // 禁止无效的正则表达式

    'no-func-assign': 2, // 禁止重复的函数声明

    'valid-typeof': 2, // 必须使用合法的typeof的值

    'no-unreachable': 2, // 不能有无法执行的代码

    'no-unexpected-multiline': 2, // 避免多行表达式

    'no-sparse-arrays': 2, // 禁止稀疏数组, [1,,2]

    'no-shadow-restricted-names': 2, // 严格模式中规定的限制标识符不能作为声明时的变量名使用

    'no-cond-assign': 2, // 禁止在条件表达式中使用赋值语句

    'no-native-reassign': 2, // 不能重写native对象

    // 代码风格

    'no-else-return': 1, // 如果if语句里面有return,后面不能跟else语句

    'no-multi-spaces': 1, // 不能用多余的空格

    'key-spacing': [
      1,
      {
        // 对象字面量中冒号的前后空格

        beforeColon: false,

        afterColon: true,
      },
    ],

    'block-scoped-var': 2, // 块语句中使用var

    'consistent-return': 2, // return 后面是否允许省略

    'accessor-pairs': 2, // 在对象中使用getter/setter

    'dot-location': [2, 'property'], // 对象访问符的位置,换行的时候在行首还是行尾

    'no-lone-blocks': 2, // 禁止不必要的嵌套块

    'no-labels': 2, // 禁止标签声明

    'no-extend-native': 2, // 禁止扩展native对象

    'no-floating-decimal': 2, // 禁止省略浮点数中的0 .5 3.

    'no-loop-func': 2, // 禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)

    'no-new-func': 2, // 禁止使用new Function

    'no-self-compare': 2, // 不能比较自身

    'no-sequences': 2, // 禁止使用逗号运算符

    'no-throw-literal': 2, // 禁止抛出字面量错误 throw "error";

    'no-return-assign': [2, 'always'], // return 语句中不能有赋值表达式

    'no-redeclare': [
      2,
      {
        // 禁止重复声明变量

        builtinGlobals: true,
      },
    ],

    'no-unused-expressions': [
      2,
      {
        // 禁止无用的表达式

        allowShortCircuit: true,

        allowTernary: true,
      },
    ],

    'no-useless-call': 2, // 禁止不必要的call和apply

    'no-useless-concat': 2,

    'no-void': 2, // 禁用void操作符

    'no-with': 2, // 禁用with

    'space-infix-ops': 2, // 中缀操作符周围要不要有空格

    'valid-jsdoc': [
      2,
      {
        // jsdoc规则

        requireParamDescription: true,

        requireReturnDescription: true,
      },
    ],

    'no-warning-comments': [
      2,
      {
        // 不能有警告备注

        terms: ['todo', 'fixme', 'any other term'],

        location: 'anywhere',
      },
    ],

    curly: 1, // 必须使用 if(){} 中的{}

    // common js
    // 常用规则
    // 规则的细节请到ESLint官方网站查看官网
    'no-duplicate-imports': 1,
    'comma-dangle': ['error', 'never'], //是否允许对象中出现结尾逗号

    'no-cond-assign': 2, //条件语句的条件中不允许出现赋值运算符

    'no-console': 2, //不允许出现console语句

    'no-constant-condition': 2, //条件语句的条件中不允许出现恒定不变的量

    'no-control-regex': 2, //正则表达式中不允许出现控制字符

    'no-debugger': 2, //不允许出现debugger语句

    'no-dupe-args': 2, //函数定义的时候不允许出现重复的参数

    'no-dupe-keys': 2, //对象中不允许出现重复的键

    'no-duplicate-case': 2, //switch语句中不允许出现重复的case标签

    'no-empty': 2, //不允许出现空的代码块

    'no-empty-character-class': 2, //正则表达式中不允许出现空的字符组

    'no-ex-assign': 2, //在try catch语句中不允许重新分配异常变量

    'no-extra-boolean-cast': 2, //不允许出现不必要的布尔值转换

    'no-extra-parens': 0, //不允许出现不必要的圆括号

    'no-extra-semi': 2, //不允许出现不必要的分号

    'no-func-assign': 2, //不允许重新分配函数声明

    'no-inner-declarations': ['error', 'functions'], //不允许在嵌套代码块里声明函数

    'no-invalid-regexp': 2, //不允许在RegExp构造函数里出现无效的正则表达式

    'no-irregular-whitespace': 2, //不允许出现不规则的空格

    'no-negated-in-lhs': 2, //不允许在in表达式语句中对最左边的运算数使用取反操作

    'no-obj-calls': 2, //不允许把全局对象属性当做函数来调用

    'no-regex-spaces': 2, //正则表达式中不允许出现多个连续空格

    'quote-props': 2, //对象中的属性名是否需要用引号引起来

    'no-sparse-arrays': 2, //数组中不允许出现空位置

    'no-unreachable': 2, //在return,throw,continue,break语句后不允许出现不可能到达的语句

    'use-isnan': 2, //要求检查NaN的时候使用isNaN()

    'valid-jsdoc': [
      'error',
      {
        requireReturn: false,

        requireParamDescription: false,

        requireReturnDescription: true,
      },
    ], //强制JSDoc注释

    'valid-typeof': [
      'error',
      {
        requireStringLiterals: true,
      },
    ], //在使用typeof表达式比较的时候强制使用有效的字符串

    'block-scoped-var': 2, //将变量声明放在合适的代码块里

    complexity: 0, //限制条件语句的复杂度

    'consistent-return': 2, //无论有没有返回值都强制要求return语句返回一个值

    curly: ['error', 'all'], //强制使用花括号的风格

    'default-case': 0, //在switch语句中需要有default语句

    'dot-notation': ['error', { allowKeywords: false, allowPattern: '' }], //获取对象属性的时候使用点号

    eqeqeq: ['error', 'smart'], //比较的时候使用严格等于

    'no-alert': 1, //不允许使用alert,confirm,prompt语句

    'no-caller': 2, //不允许使用arguments.callee和arguments.caller属性

    'guard-for-in': 0, //监视for in循环,防止出现不可预料的情况

    'no-div-regex': 2, //不能使用看起来像除法的正则表达式

    'no-else-return': 0, //如果if语句有return,else里的return不用放在else里

    'no-labels': [
      'error',
      {
        allowLoop: false,

        allowSwitch: false,
      },
    ], //不允许标签语句

    'no-eq-null': 2, //不允许对null用==或者!=

    'no-eval': 2, //不允许使用eval()

    'no-extend-native': 2, //不允许扩展原生对象

    'no-extra-bind': 2, //不允许不必要的函数绑定

    'no-fallthrough': 2, //不允许switch按顺序全部执行所有case

    'no-floating-decimal': 2, //不允许浮点数缺失数字

    'no-implied-eval': 2, //不允许使用隐式eval()

    'no-iterator': 2, //不允许使用__iterator__属性

    'no-lone-blocks': 2, //不允许不必要的嵌套代码块

    'no-loop-func': 2, //不允许在循环语句中进行函数声明

    'no-multi-spaces': 2, //不允许出现多余的空格

    'no-multi-str': 2, //不允许用\来让字符串换行

    'no-global-assign': 2, //不允许重新分配原生对象

    'no-new': 2, //不允许new一个实例后不赋值或者不比较

    'no-new-func': 2, //不允许使用new Function

    'no-new-wrappers': 2, //不允许使用new String,Number和Boolean对象

    'no-octal': 2, //不允许使用八进制字面值

    'no-octal-escape': 2, //不允许使用八进制转义序列

    'no-param-reassign': 0, //不允许重新分配函数参数"no-proto": 2, //不允许使用__proto__属性

    'no-redeclare': 2, //不允许变量重复声明

    'no-return-assign': 2, //不允许在return语句中使用分配语句

    'no-script-url': 2, //不允许使用javascript:void(0)

    'no-self-compare': 2, //不允许自己和自己比较

    'no-sequences': 2, //不允许使用逗号表达式

    'no-throw-literal': 2, //不允许抛出字面量错误 throw "error"

    'no-unused-expressions': 2, //不允许无用的表达式

    'no-void': 2, //不允许void操作符

    'no-warning-comments': [1, { terms: ['todo', 'fixme', 'any other term'] }], //不允许警告备注

    'no-with': 2, //不允许使用with语句

    radix: 1, //使用parseInt时强制使用基数来指定是十进制还是其他进制

    'vars-on-top': 0, //var必须放在作用域顶部

    'wrap-iife': [2, 'any'], //立即执行表达式的括号风格

    yoda: [2, 'never', { exceptRange: true }], //不允许在if条件中使用yoda条件

    strict: [2, 'function'], //使用严格模式

    'no-catch-shadow': 2, //不允许try catch语句接受的err变量与外部变量重名"no-delete-var": 2, //不允许使用delete操作符

    'no-label-var': 2, //不允许标签和变量同名

    'no-shadow': 2, //外部作用域中的变量不能与它所包含的作用域中的变量或参数同名

    'no-shadow-restricted-names': 2, //js关键字和保留字不能作为函数名或者变量名

    'no-undef': 2, //不允许未声明的变量

    'no-undef-init': 2, //不允许初始化变量时给变量赋值undefined

    'no-undefined': 2, //不允许把undefined当做标识符使用

    'no-unused-vars': [2, { vars: 'all', args: 'after-used' }], //不允许有声明后未使用的变量或者参数

    'no-use-before-define': [2, 'nofunc'], //不允许在未定义之前就使用变量"indent": 2, //强制一致的缩进风格

    'brace-style': [2, '1tbs', { allowSingleLine: false }], //大括号风格

    camelcase: [2, { properties: 'never' }], //强制驼峰命名规则

    'comma-style': [2, 'last'], //逗号风格

    'consistent-this': [0, 'self'], //当获取当前环境的this是用一样的风格

    'eol-last': 2, //文件以换行符结束

    'func-names': 0, //函数表达式必须有名字

    'func-style': 0, //函数风格,规定只能使用函数声明或者函数表达式

    'key-spacing': [2, { beforeColon: false, afterColon: true }], //对象字面量中冒号的前后空格

    'max-nested-callbacks': 0, //回调嵌套深度

    'new-cap': [2, { newIsCap: true, capIsNew: false }], //构造函数名字首字母要大写

    'new-parens': 2, //new时构造函数必须有小括号

    'newline-after-var': 0, //变量声明后必须空一行

    'no-array-constructor': 2, //不允许使用数组构造器

    'no-inline-comments': 0, //不允许行内注释

    'no-lonely-if': 0, //不允许else语句内只有if语句

    'no-mixed-spaces-and-tabs': [2, 'smart-tabs'], //不允许混用tab和空格

    'no-multiple-empty-lines': [2, { max: 2 }], //空行最多不能超过两行

    'no-nested-ternary': 2, //不允许使用嵌套的三目运算符

    'no-new-object': 2, //禁止使用new Object()

    'fun-call-spacing': 2, //函数调用时,函数名与()之间不能有空格

    'no-ternary': 0, //不允许使用三目运算符

    'no-trailing-spaces': 2, //一行最后不允许有空格

    'no-underscore-dangle': 2, //不允许标识符以下划线开头

    'no-extra-parens': 0, //不允许出现多余的括号

    'one-var': 0, //强制变量声明放在一起

    'operator-assignment': 0, //赋值运算符的风格

    'padded-blocks': [2, 'never'], //块内行首行尾是否空行

    'quote-props': 0, //对象字面量中属性名加引号

    quotes: [1, 'single', 'avoid-escape'], //引号风格

    semi: [2, 'always'], //强制语句分号结尾

    'semi-spacing': [2, { before: false, after: true }], //分后前后空格

    'sort-vars': 0, //变量声明时排序

    'space-before-blocks': [2, 'always'], //块前的空格

    'space-before-function-paren': [2, { anonymous: 'always', named: 'never' }], //函数定义时括号前的空格

    'space-infix-ops': [2, { int32Hint: true }], //操作符周围的空格

    'keyword-spacing': 2, //关键字前后的空格

    'space-unary-ops': [2, { words: true, nonwords: false }], //一元运算符前后不要加空格

    'wrap-regex': 2, //正则表达式字面量用括号括起来

    'no-var': 0, //使用let和const代替var

    'generator-star-spacing': [2, 'both'], //生成器函数前后空格

    'max-depth': 0, //嵌套块深度

    'max-len': 0, //一行最大长度,单位为字符

    'max-params': 0, //函数最多能有多少个参数

    'max-statements': 0, //函数内最多有几个声明

    'no-bitwise': 0, //不允许使用位运算符

    'no-plusplus': 0, //不允许使用++ --运算符},    // 可以自己自定一些规则
  },
};

Commitlint 配置

@commitlint/cli 可以检查提交信息

@commitlint/config-conventional 是提交规范的配置包

npm i @commitlint/cli @commitlint/config-conventional -D
根目录下新建 commitlint.config.js 文件
/*
规范commit日志 https://commitlint.js.org */ const types = [ 'build', // 主要目的是修改项目构建系统(例如glup,webpack,rollup的配置等)的提交 'ci', // 修改项目的持续集成流程(Kenkins、Travis等)的提交 'chore', // 构建过程或辅助工具的变化 'docs', // 文档提交(documents) 'feat', // 新增功能(feature) 'fix', // 修复 bug 'pref', // 性能、体验相关的提交 'refactor', // 代码重构 'revert', // 回滚某个更早的提交 'style', // 不影响程序逻辑的代码修改、主要是样式方面的优化、修改 'test', // 测试相关的开发, ], typeEnum = { rules: { 'type-enum': [2, 'always', types], }, value: () => { return types; }, }; module.exports = { extends: ['@commitlint/config-conventional'], /* Level [0..2]: 0 disables the rule. For 1 it will be considered a warning for 2 an error. https://commitlint.js.org/#/reference-rules */ rules: { 'type-enum': typeEnum.rules['type-enum'], 'subject-full-stop': [0, 'never'], 'subject-case': [0, 'never'], }, };

 

配置 lint-staged 规则

package.json 里 添加

"lint-staged": {
    "*.{js,vue}": [
      "prettier --write",
      "eslint --fix",
    ],
    "*.less": [
      "stylelint --fix"
    ]
}

配置 husky 检验钩子

 package.json 里 添加

"husky": {
    "hooks": {
      "pre-commit": "lint-staged", // 可以配置指令  下面 是配置文件 
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
}

 

 

依赖目录

{
    "husky": "^4.2.5",
    "lint-staged": "^11.0.1",
    "eslint": "^6.8.0",
    "eslint-plugin-html": "^6.1.0",
    "eslint-plugin-vue": "^6.2.2",
    "babel-eslint": "^10.1.0",
    "stylelint": "^13.13.1",
    "stylelint-config-recess-order": "^2.4.0",
    "stylelint-config-standard": "^22,
    "@commitlint/cli": "^12.1.4",
    "@commitlint/config-conventional": "^12.1.4",
}

  

posted @ 2022-10-17 10:37  玖捌  阅读(545)  评论(0)    收藏  举报