花十分钟的时间武装你的代码库

语言: CN / TW / HK

「深度学习福利」大神带你进阶工程师,立即查看>>>

当我们的代码库有很多人维护时,经常会出现代码风格不一致或者代码质量不过关,提交信息杂乱的情况,当然啦,即使是一个人的代码库,有的时候,自己写代码时不太注意细节,也会出现风格不一致的情况。

本文正是为了解决这个问题而生,阅读本篇文章并不需要很长时间,如果你的代码库还没有进行这些配置,正是你大展身手的好时机,武装一下你的代码库。

1. 规范 commit 信息

首先,看下 angular 的代码库的 commit 记录,如图:

我们可以利用 commitizenhusky 来规范代码库的 commit

安装以下依赖:
npm install @commitlint/cli @commitlint/config-conventional husky  -D

如果你还没有安装过 commitizen,那么先全局安装:

npm install commitizen -g
在 package.json 中增加 husky 字段。
{
    "husky": {
        "hooks": {
            "commit-msg""commitlint -E HUSKY_GIT_PARAMS"
        }
    },
}

huskygit hook 工具,使用 husky,我们可以方便的在 package.json 中配置 git hook 脚本,例如: pre-commitpre-pushcommit-msg 等的。

创建 commitlint.config.js 文件
module.exports = {
    extends: ["@commitlint/config-conventional"],
};

此刻开始,请使用 git cz 来替代 git commit 提交信息,我们来看看,假设我们随便写一个 git commit -m 'fixbug' 会提示什么?

使用 git cz 来进行填写 commit 的内容。

git cztype 说明:

虽然,我们现在已经可以规范提交信息了,但是我们可能不喜欢默认的交互,例如,一个精简的描述就可以了,不希望再提示我去写详细的描述,那么就可以使用 cz-customizable 来进行定制。

自定义提交说明

安装 cz-customizable
npm install cz-customizable -D

cz-customizable 是可自定义的 Commitizen 插件,可帮助实现一致的 commit message

cz-customizable 适合大型团队去自定义 scope,和 commit type

新建 .cz-config.js

在项目根目录下创建 .cz-config.js 文件:

官方提供了一份配置信息,可以去这个地址查看:https://github.com/leoforfree/cz-customizable/blob/master/cz-config-EXAMPLE.js

//.cz-config.js
module.exports = {
  types: [
    { value'feat'name'feat:     A new feature' },
    { value'fix'name'fix:      A bug fix' },
    { value'docs'name'docs:     Documentation only changes' },
    {
      value'style',
      name:
        'style:    Changes that do not affect the meaning of the code\n            (white-space, formatting, missing semi-colons, etc)',
    },
    {
      value'refactor',
      name'refactor: A code change that neither fixes a bug nor adds a feature',
    },
    {
      value'perf',
      name'perf:     A code change that improves performance',
    },
    { value'test'name'test:     Adding missing tests' },
    {
      value'chore',
      name:
        'chore:    Changes to the build process or auxiliary tools\n            and libraries such as documentation generation',
    },
    { value'revert'name'revert:   Revert to a commit' },
    { value'WIP'name'WIP:      Work in progress' },
  ],

  scopes: [{ name'accounts' }, { name'admin' }, { name'exampleScope' }, { name'changeMe' }],

  allowTicketNumberfalse,
  isTicketNumberRequiredfalse,
  ticketNumberPrefix'TICKET-',
  ticketNumberRegExp'\\d{1,5}',

  // it needs to match the value for field type. Eg.: 'fix'
  /*
  scopeOverrides: {
    fix: [
      {name: 'merge'},
      {name: 'style'},
      {name: 'e2eTest'},
      {name: 'unitTest'}
    ]
  },
  */

  // override the messages, defaults are as follows
  messages: {
    type"Select the type of change that you're committing:",
    scope'\nDenote the SCOPE of this change (optional):',
    // used if allowCustomScopes is true
    customScope: 'Denote the SCOPE of this change:',
    subject'Write a SHORT, IMPERATIVE tense description of the change:\n',
    body'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
    breaking'List any BREAKING CHANGES (optional):\n',
    footer'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
    confirmCommit'Are you sure you want to proceed with the commit above?',
  },

  allowCustomScopestrue,
  allowBreakingChanges: ['feat''fix'],
  // skip any questions you want
  skipQuestions: ['body'],

  // limit subject length
  subjectLimit: 100,
};
  • types: 描述修改的性质是什么,是bugfix还是feat,在这里进行定义。

  • scopes: 定义之后,我们就可以通过上下键去选择 scope

  • scopeOverrides: 针对每一个type去定义scope

  • allowBreakingChanges: 如上设置为 ['feat', 'fix'],只有我们type选择了 feat 或者是 fix,才会询问我们 breaking message.

  • allowCustomScopes: 设置为 true,在 scope 选择的时候,会有 emptycustom 可以选择,顾名思义,选择 empty 表示 scope 缺省,如果选择 custom,则可以自己输入信息

  • skipQuestions: 指定跳过哪些步骤,例如跳过我们刚刚说的详细描述,设置其为 scope: ['body'],假设我们的项目也不会涉及到关联 issue,我们可以设置其为 scope: ['body', 'footer']

  • subjectLimit: 描述的长度限制

这里我就不一一演示每个字段修改之后的情况了,根据字段的说明,建议如果想自定义提交规则,在本地进行修改验证,公司内部的代码库不需要管理 issue,另外,我不喜欢写长描述,所以我把 bodyfooterskip 掉了。

cz-customizable 会首先在项目根目录下寻找: .cz-config.js.config/cz-config.js,如果找不到,会去主目录寻找。我们也可以在 package.json 中手动去指定配置文件的路径。

"config": {
    "commitizen": { 
        "path""node_modules/cz-customizable"
    },
    "cz-customizable": {
        "config""config/path/to/my/config.js"
    }
}

现在,我们已经规范了 commit 信息,但是没有对提交的代码进行规范,在一个代码库中,经常出现2个空格/4个空格混用,有些地方写 ;,有些不写 ;,风格不统一。例如,我们希望提交到git库的代码,都能够通过 eslint 检查或者是通过测试。我们可以借助于 pre-commit 这个钩子来做这些事情。

2. 代码提交前检查

安装依赖
npm install lint-staged -D
使用 pre-commit 的 hook
"husky": {
    "hooks": {
        "pre-commit""lint-staged"
    }
},
"lint-staged": {
    "**/*.js": [
        "prettier --write"
        "eslint"
    ]
}

这样配置之后,每次提交的时候,都会对要提交的文件(并不是对整个项目)进行 prettier 格式化和 eslint 检查,都通过之后,才能 commit 成功。

eslint 和 prettier 配置

我的项目是 react 项目,下面是我进行的配置。

安装 eslintprettier 相关依赖:

npm install eslint eslint-config-prettier eslint-plugin-promise eslint-plugin-react eslint-plugin-react-hooks prettier babel-eslint -D

新建 .prettierrc.js

当然啦,你也可以在 package.jsonprettier 字段中配置,这里我配置成了独立的文件,以便后期维护。

module.exports = {
  printWidth100//长度超过100断行
  singleQuote: true,//使用单引号
};

如果你有一些文件不需要 prettier 进行格式化,那么可以新建一个 .prettierignore 文件,如下:

dist
node_modules
public

新建 .eslintrc.js 文件

以下是我的配置:

module.exports = {
  settings: {
    react: {
      pragma'React',
      version'detect'
    }
  },
  // babel parser to support ES6/7 features
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion7,
    ecmaFeatures: {
      experimentalObjectRestSpreadtrue,
      jsxtrue
    },
    sourceType'module'
  },
  extends: [
    'prettier'
    'prettier/react'
  ],
  plugins: [
    'promise'
    'react'
    'react-hooks'
  ],
  env: {
    browsertrue,
    es6true,
    nodetrue
  },
  rules: {
    'no-compare-neg-zero'2//禁止与 -0 进行比较
    'no-cond-assign'2//禁止条件表达式中出现赋值操作符
    'no-console'1//禁用 console
    'no-constant-condition'1//禁止在条件中使用常量表达式
    'no-control-regex'1//禁止在正则表达式中使用控制字符
    'no-debugger'2//禁用 debugger
    'no-dupe-args'2//禁止 function 定义中出现重名参数
    'no-dupe-keys'2//禁止对象字面量中出现重复的 key
    'no-duplicate-case'2//禁止出现重复的 case 标签
    'no-const-assign'1//禁止修改const声明的变量
    'no-empty'1//禁止出现空语句块
    'no-empty-character-class'2//禁止在正则表达式中使用空字符集
    'no-ex-assign'2//禁止对 catch 子句的异常参数重新赋值
    'no-extra-boolean-cast'1//禁止不必要的布尔转换
    'no-extra-semi'1//禁止不必要的分号
    'no-func-assign'2//禁止对 function 声明重新赋值
    'no-inner-declarations'0//禁止在嵌套的块中出现变量声明或 function 声明,ES6中无需禁止
    'no-invalid-regexp'2//禁止 RegExp 构造函数中存在无效的正则表达式字符串
    'no-irregular-whitespace'1//禁止在字符串和注释之外不规则的空白
    'no-obj-calls'2//禁止把全局对象作为函数调用,比如Math() JSON()
    'no-regex-spaces'1//禁止正则表达式字面量中出现多个空格
    'no-sparse-arrays'1//禁用稀疏数组
    'no-unexpected-multiline'1//禁止出现令人困惑的多行表达式
    'no-unreachable'1//禁止在return、throw、continue 和 break 语句之后出现不可达代码
    'no-unsafe-finally'2//禁止在 finally 语句块中出现控制流语句
    'no-unsafe-negation'1//禁止对关系运算符的左操作数使用否定操作符
    'use-isnan'2//要求使用 isNaN() 检查 NaN,如 isNaN(foo),而非foo == NaN
    'valid-typeof'2//强制 typeof 表达式与有效的字符串(如: 'undefined', 'object', 'boolean', 'number', 'string', 'function','symbol')进行比较
    'no-case-declarations'1//不允许在 case 子句中使用词法声明
    'no-empty-pattern'2//禁止使用空解构模式
    'no-fallthrough'2//禁止 case 语句落空
    'no-global-assign'2//禁止对原生对象或只读的全局对象进行赋值
    'no-octal'1//禁用八进制字面量
    'no-redeclare'1//禁止多次声明同一变量
    'no-self-assign'1//禁止自我赋值
    'no-unused-labels'1//禁用出现未使用过的标
    'no-useless-escape'1//禁用不必要的转义字符
    'no-delete-var'2//禁止删除变量
    'no-undef'2//禁用使用未声明的变量,除非它们在 /*global */ 注释中被提到
    'no-unused-vars'1//禁止出现未使用过的变量
    'constructor-super'2//要求在构造函数中有 super() 的调用
    'no-class-assign'2//禁止给类赋值
    'no-dupe-class-members'2//禁止类成员中出现重复的名称
    'no-new-symbol'2//禁止 Symbol 和 new 操作符一起使用
    'no-this-before-super'2//禁止在构造函数中,在调用 super() 之前使用 this 或 super
    'require-yield'2//要求 generator 函数内有 yield
    'no-mixed-spaces-and-tabs'1//要求不适用space,tab混用
    'react/forbid-prop-types': [1, { forbid: ['any'] }], //禁止某些propTypes
    'react/prop-types'1//没用对props类型进行校验
    'react/jsx-closing-bracket-location'1//在JSX中验证右括号位置
    'react/jsx-curly-spacing': [1, { when'never'childrentrue }], //在JSX属性和表达式中加强或禁止大括号内的空格。
    'react/jsx-key'2//在数组或迭代器中验证JSX具有key属性
    'react/jsx-max-props-per-line': [1, { maximum1 }], // 限制JSX中单行上的props的最大数量
    'react/jsx-no-duplicate-props'2//防止在JSX中重复的props
    'react/jsx-no-undef'1//在JSX中禁止未声明的变量
    'react/no-string-refs'1//Using string literals in ref attributes is deprecated
    'react/jsx-uses-react'1//防止反应被错误地标记为未使用
    'react/jsx-uses-vars'1//防止在JSX中使用的变量被错误地标记为未使用
    'react/no-danger'1//防止使用危险的JSX属性
    'react/no-did-update-set-state'2//防止在componentDidUpdate中使用setState
    'react/no-did-mount-set-state'0//防止在componentDidUpdate中使用setState
    'react/no-direct-mutation-state'2//防止this.state赋值
    'react/no-unknown-property'2//防止使用未知的DOM属性
    'react/prefer-es6-class'1//为React组件强制执行ES5或ES6类
    'react/react-in-jsx-scope'0//使用JSX时,必须要引入React
    'react/sort-comp'0//强制组件方法顺序
    'react/sort-prop-types'0//强制组件属性顺序
    'react/jsx-sort-props'1,
    'react/no-deprecated'1//不使用弃用的方法
    'react/jsx-equals-spacing'1//在JSX属性中强制或禁止等号周围的空格
    'react/wrap-multilines'0,
    'comma-dangle'1//对象字面量项尾不能有逗号
    'react/no-multi-comp'0//防止每个文件有多个组件定义
    'flowtype/generic-spacing'0//泛型对象的尖括号中类型前后的空格规范
    'flowtype/space-after-type-colon'0//类型注解分号后的空格规范
    // react-hooks
    'react-hooks/rules-of-hooks''error',
    'react-hooks/exhaustive-deps''warn'
  }
};

现在,再也不能随心所欲往你的代码库提交文件啦,不过 eslintprettier 的规则要和团队的成员协商制定哈~

参考资料:

  1. https://juejin.im/post/6844903831893966856

  2. react-native-web 代码库配置

学习交流

  • 关注公众号【前端宇宙】,每日获取好文推荐
  • 添加微信,入群交流

“在看和转发” 就是最大的支持


本文分享自微信公众号 - 前端宇宙(gh_8184da923ced)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

分享到: