dogc之eslint+pritter+husky+lint-stage

1,492 阅读8分钟

前言

熟话说,不以规矩,不能成方圆。良好的代码规范,不管是对于个人还是团队都非常重要。为了提供代码质量统一代码规范,我选择了eslintprettier搭配来使用,并且在最后提交到git仓库时用husky搭配lint-stage进行预检查,保证线上仓库的代码符合要求。

eslint和prettier区别

ESLint 主要解决的是代码质量问题,代码质量出问题意味着程序有潜在Bug。比如:

Prettier 主要解决的是代码风格问题,风格问题充其量也只是看着不爽。比如:

eslint配置

  // 首先安装eslint
  npm install eslint -D
  // 然后生成.eslintrc.json配置文件
  npx eslint init
  // 配置适合自己或者整个团队的代码规则
  // 配置完成之后
  npx eslint [文件路径]
  • parser ESLint的默认解析器和(espree)核心规则只支持最新的最终ECMAScript标准,不支持Babel提供的实验性(如新特性)和non-standard(如流或TypeScript类型)语法,此时这里可以自定义解析器Babel-ESLint@typescript-eslint/parser
{
    "parser": "@typescript-eslint/parser"
    // 先调用typescript模块,生成标准的 TypeScript AST,
    // 然后再将它转换成兼容 ESLint的ESTree
    // 可参考 https://www.jianshu.com/p/ade75072c70a
    // 或者
    "parser":"babel-eslint"
    // 代码将由Babel的解析器(使用Babel配置文件中指定的配置)解析,
    // 并将生成的AST转换为ESLint可以理解的ESTree兼容结构
    // 可参考 https://www.5axxw.com/wiki/content/8ygnvk
}

不管是哪个解析器,最终目的都是转化成eslint兼容的ESTree

  • parserOptions
  // 解析器选项
  // 指定要支持的 JavaScript 语言版本的选项
  // 应该始终设置解析器选项:
  // 1. 使用默认解析器的时候,ESLint 需要 parserOptions 配置属性才能使 ESLint 与 ECMAScript 5 中未包含的功能正常配合使用
  // 2. 即使使用其他的解析器。解析器会被传入 parserOptions,但是不一定会使用它们来决定功能特性的开关
  "parserOptions": {
    // ecma版本:支持 ES6 语法,默认支持 ECMAScript 5 语法,可以选值有: 3, 5, 6, 7, 8, 9, 10, 11, 12
    // 注意的是不会自动启用支持 ES6 新的全局变量
    "ecmaVersion": 6,
    // 源码类型:如果你的代码在 ECMAScript 模块中可以设置为 "module",默认为 "script"
    // 如果不设置未 "module",那么 export、import 就会报错
    "sourceType": "module",
    // 以对象的形式指定您要使用哪些附加语言特性
    "ecmaFeatures": {
      "globalReturn": false, // 允许在 global 作用域使用 return 语句
      "impliedStrict": false, // 如果 ecmaVersion 设置为 5 或者更高的时候,在 global 作用域启用严格模式。implied 是隐性的意思
      "jsx": false, // 支持 JSX 语法
    },
  },
  • env 设置编码的环境。
  // 设置环境
  // 设置您的脚本在哪种环境中运行。每个环境都会带来一组特定的预定义全局变量。
  // 可以简单理解为批量设置全局变量,这些环境不是互斥的,因此您一次可以定义多个环境。
  // 开启全部环境
  "env": {
    "browser": true,             // 浏览器全局变量
    "node": true,                // Node.js 全局变量和 Node.js 作用域
    "commonjs": true,            // CommonJS 全局变量和 CommonJS 作用域 (启用此环境用于使用 Browserify/WebPack 的 browser-only 代码)
    "es6": true,                 // 启用除 modules 以外的所有 ECMAScript 6 特性  (这会自动将 `ecmaVersion` 解析器选项设置为 6)
    "es2017": true,              // 添加所有 ECMAScript 2017 的全局变量并且自动设置 `ecmaVersion` 解析器选项设置为 8
    "es2020": true,              // 添加所有 ECMAScript 2020 的全局变量并且自动设置 `ecmaVersion` 解析器选项设置为 11
    "es2021": true,              // 添加所有 ECMAScript 2021 的全局变量并且自动设置 `ecmaVersion` 解析器选项设置为 12
    "amd": true,                 // 根据 amd 规范定义 `require()` 和 `define()` 作为全局变量
  }

更多环境可查看

  • globals 设置全局变量。
  // 全局变量
  // 如果访问未在同一文件中定义的变量,将会出现 no-undef 警告。如果要在文件内部使用全局变量,为了让 ESLint 不会出现警告,需要进行定义。
  // readonly-可读不可写 writable-可读可写
  "globals": {
    "WX": "readonly",
    "Wang":"writable"
  }
  • extends 规则集,批量扩展规则。对于不同项目,如果希望使用相同的 rules,直接复制粘贴显然不是一个好方法,一是 rules 太多,配置文件会显得很乱,二是无法同步更新。

推荐使用的方法是把所需的 rules 抽离成一个 npm 包,需要的时候再通过 extends 引用。而且对于这些抽离出来的包,有着统一的命名规范。

extends 的模块名称以 eslint-config- 开头,例如eslint-config-wang

"extends": [
    "eslint-config-wang",  // 全称
    "wang",     // 简写
    "eslint:recommended",          // eslint官方提供的规则集
    "plugin:@typescript-eslint/recommended" // typescirpt规则集
],
// 可以无限扩充,后面的规则会覆盖前面的规则 
// 前提是plugin里面已经定义了这些规则,extends的作用是开启plugin定义的规则
// 形如plugin: ,会自动引入plugin,不用在plugin配置项里面再写一遍
  • rules 逐条配置规则
rules:{
   // 禁用 console
   "no-console":0,
 
   // 要求使用 let 或 const 而不是 var
   "no-var":0,
   
   // 优先级最高,会覆盖extends的规则,同样也是要先配置plugin,plugin定义的规则才会生效。
}
  • plugin 虽然官方提供了很多规则,但是总有覆盖不到的情况。这时候可以使用 plugin 定义自己的规则。与 extends 类似的命名规则,把 config 替换成 plugin 即可。例如:eslint-plugin-wang。 引入 plugin 可以理解为引入了额外的 rules,需要在 rulesextends 中定义后才会生效。
   plugins: ['wang'],
   // 如果在extends引入plugin:wang/recommended,plugin会被自动引入

为了不每次都执行命令来检查代码,简化开发,vscdoe可安装eslint插件来自动标记错误,eslint插件可自动检测.eslintrc.json,在编码的同时就能发现错误。

prettier配置

  // 安装prettier
  npm install prettier -D

创建配置文件 .prettierrc.js,下面是配置文件:

module.exports = {
  // 最大长度80个字符
  printWidth: 80,
  // 使用单引号, 默认false(在jsx中配置无效, 默认都是双引号)
  singleQuote: false,
  // 行末分号, 默认true
  semi: true,
  // JSX双引号
  jsxSingleQuote: false,
  // 尽可能使用尾随逗号(包括函数参数),默认none,可选 none|es5|all
  // es5 包括es5中的数组、对象
  // all 包括函数对象等所有可选
  trailingComma: "all",
  // 在对象文字中打印括号之间的空格。 默认true
  bracketSpacing: true,
  // 箭头函数参数括号 默认avoid 可选 avoid| always
  // avoid 能省略括号的时候就省略 例如x => x
  // always 总是有括号
  arrowParens: "avoid",
  // 在文件顶部插入一个特殊的 @format 标记,指定文件格式需要被格式化。
  insertPragma: false,
  // 行尾换行格式
  endOfLine: "auto",
  // html空格敏感度
  htmlWhitespaceSensitivity: "ignore",
  // tab缩进大小,默认为2
  tabWidth: 2,
  // 使用tab缩进还是空格,默认false
  useTabs: false,
  // vue缩进脚本和样式
  vueIndentScriptAndStyle: false,
  // > 标签放在最后一行的末尾,而不是单独放在下一行 默认false
  jsxBracketSameLine: false,

  insertPragma: false,

  requirePragma: false,
};

最后执行下面命令来fix代码风格

npx prettier --write [文件路径]

为了不每次都执行命令来格式化代码,简化开发,vscode可安装prettier插件,保存自动根据配置文件来格式化代码,非常方便。

eslint和prettier配置冲突

eslintprettier各自详细的配置这里不多说,社区里面有很多详细的配置。这里主要讲一下eslintprettier搭配使用的注意点。因为eslint在代码检查的过程中,也会对代码风格进行检查,如果prettier的配置和eslint的规则冲突,则会陷入死循环。解决方法如下:

npm install eslint-plugin-prettier -D

然后在.eslintrc.json文件中配置:

"extends": ["plugin:prettier/recommended"]

即可。具体可看这里

husky

husky是一个为 git 客户端增加 hook 的工具。在执行git命令之前我们可以自定义某些的操作,比如 pre-commit 钩子就会在你执行 git commit 的触发,我们可以在 pre-commit 中实现一些比如 lint 检查、单元测试、代码美化等操作。

  • 首先安装husky(我装的是v7+,v7之前的与下面的配置不一样,可以自行百度)
npm install husky -D
  • 然后配置运行npx husky install命令,执行完命令之后,会出现.husky的目录,如下图

截屏2021-09-14 上午10.17.52.png

当执行完上面的步骤之后,在.husky目录下是没有commit-msgpre-commit两个目录的,我们要手动添加hooks,添加完成之后,husky会自动执行我们添加的操作。

 // 添加pre-commit勾子
 npx husky add .husky/pre-commit "npx lint-staged --allow-empty $1"
 // 添加commit-msg勾子
 npx husky add .husky/commit-msg "npx commitlint --edit $1"

lint-stage

lint-stage一个仅仅过滤出 Git 代码暂存区文件(被 git add 的文件)的工具;这个很实用,因为我们如果对整个项目的代码做一个检查,可能耗时很长,如果是老项目,要对之前的代码做一个代码规范检查并修改的话,这可能就麻烦了,可能导致项目改动很大。所以这个 lint-staged,对团队项目和开源项目来说,是一个很好的工具,它是对个人要提交的代码的一个规范和约束。

如果对于husky和lint-stage不清楚的话可以点击后面的两个链接,里面有详细的介绍。

传送门1

传送门2

最后送上dogc仓库地址