eslint-prettier-husky-lint-staged

ESLint + Prettier + Husky + lint-staged 打造代码检查工作流

记录搭建代码检查工作流的相关问题

基本介绍

  • ESLint
    • 代码检查工具
    • 特点
      • 代码静态检查
        • 提前发现低级语法错误
      • 代码风格检查
        • 检查代码风格
    • 关于eslint的配置可以查阅我之前的文章,有详细解释
  • Prettier
    • 代码格式化工具
    • 特点
      • 有一套自己的格式化规范
      • 基本支持前端涉及的所有语言
        • js、jsx、css、html、md等等
  • ESLint、Prettier 二者异同
    • eslint还是侧重于代码静态检查、prettier侧重于代码格式化
      • eslint使用--fix也可以根据特定代码风格进行一些格式化工作;
  • Husky
    • git中提供precommit、prepush钩子,可在其中执行一些脚本
  • lint-staged
    • 可针对添加到git 暂存区中不同格式的文件,分别执行不同的脚本

工具介绍

ESLint 相关

  • 通过npm install eslint安装的
    • 可以用来执行eslint 命令
      • eslint --fixeslitn --ext .js,.vue src
    • 通过webpack中的eslint-loader可以实现保存时自动修复
  • VSCode中的扩展ESLint
    • 它会读取项目中的eslint 配置文件,然后启动一个lint服务,在vscode中智能提示不符合项目eslint 配置的代码
    • 通过配置eslint.autoFixOnSave,可以实现保存时,根据配置文件规则,自动修复一些代码问题(大部分都是一些代码风格相关的问题)
  • eslint-loader
    • webpack中配合eslint使用的loader
      • 通过配置可实现在每次打包时,自动 lint;如用 vue-cli2.x 初始化的项目中下面代码
1
2
3
4
5
6
7
8
9
10
11
12
13
module:{
rules:[
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre', // 遇到js、vue文件时,会第一个调用此loader;
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
]
}
  • eslint-friendly-formatter
    • 可以输出更友好的错误提示;如包含违反规则的文件地址和规则解释网址

Prettier 相关

  • 通过npm install prettier安装的prettier cli
    • 可以调用prettier的一些命令;如prettier --wirte test.js来实现test.js的格式化
      • 更多命令可查看https://prettier.io/docs/en/cli.html
    • 会读取项目中的.pretterrc配置文件
  • VSCode中的扩展Prettier
    • 本质是内部调用pretter-cli
    • 此扩展内部内置了prettier格式化规则,不过只暴露了极少的配置选项。
    • 配置读取优先级
      • 会优先读取.prettierrc文件
      • 不存在则读取.editorconfig文件
      • 其次读取插件自身配置选项
    • 可以配合ESLint、TSLint使用
      • prettier.eslintIntegration选项
        • 设置为true后,内部会使用eslint-prettier替换prettier-cli
          • eslint-pretter
            • 会将格式化的代码传递给eslint --fix
            • Code ➡️ prettier ➡️ eslint –fix ➡️ Formatted Code

vetur

  • VSCode中的vue扩展,开发vue必备
    • 自带lint功能(需要配合eslint插件使用)
    • 自带format功能

ESLint+Prettier 相关

  • eslint-config-prettier
    • 关闭eslint中与prettier冲突的rules
  • eslint-plugin-prettier
    • 会对比格式化前后的代码,将不一致的地方标记为错误,在 eslint 中抛出

VSCode 的设置

  • editer.autoFormatOnSave
    • 编辑器的自动格式化,会调用一个格式化器
    • 它是总开关,若为 false,所有格式化工具将不能在保存时自动格式化

目标

  • 代码的检查和格式化工作,在项目内调用命令即可完成,无需依赖编辑器配置;
  • 针对使用vue-cli创建的项目
    • 针对js、vue文件使用vue-cli官方推荐的的规则来检查(我们团队习惯使用plugin:vue/recommended
    • 其它类型文件不需要lint,直接使用prettier来做格式化工作

直接启用 vue-cli 内部集成的 eslint

  • vue-cli创建的项目内部已经集成了eslint,并配置好了相关配置;我们只需要安装相关依赖,并在配置中启用即可
    • 开启后,在开发环境就可在webpack每次bundle时自动lint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// build/webpack.base.conf.js

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
const createLintingRule = () => ({
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
})
...

// config/index.js

module.exports = {
dev:{
...
useEslint:true // 开启即可
}
  • 优缺点
    • 优点
      • 这是最快捷、最快速的办法
    • 缺点
      • webpack每次bundle时,都会进行全局lint,效率较低;
        • 可以通过配置cache有所缓解
      • eslint仅针对.js、.vue实现了检查和格式化,但其它文件如.md的格式化并未实现

ESLint + Prettier 配合使用

ESLint + Prettier 如何配合使用

  • ESLint 侧重代码静态检查
  • Prettier 侧重代码风格格式化
  • 何不将二者结合起来呢?
  • Prettier官方文档介绍了 3 种将Prettier结合ESLint使用的方法
  1. 使用eslint-plugin-prettier
    • 会对比格式化前后的代码,将不一致的地方标记为错误,在 eslint 中抛出
1
2
3
4
5
6
7
// .eslintrc
{
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
  1. 使用eslint-config-prettier
    • 关闭eslint中与prettier冲突的rules
1
2
3
4
// .eslintrc
{
"extends": ["prettier"]
}
  1. 使用"plugin:prettier/recommended"
    • 结合了 1、2 方法;推荐使用
1
2
3
4
// .eslintrc
{
"extends": ["plugin:prettier/recommended"]
}
  • 针对非vue项目,这么配置就可以在eslint --fix时使用eslint做代码检查,使用prettier做格式化了
  • 二者结合使用时,可能会遇到二者格式化相关规则冲突的问题,我们在vue项目中就遇到了一些问题

结合使用时遇到的问题

  • 我们团队内部习惯使用plugin:vue/recommendedstandard规则
  • 我们尝试将其同Prettier格式化相关规则结合一起
1
2
3
{
"extends": ["plugin:vue/recommended","plugin:prettier/recommended","standard"]
}
  • 我们发现保存自动格式化时"plugin:vue/recommended","plugin:prettier/recommended"这两个规则会产生很多冲突
    • 例如,二者会因为传递给组件的props是否需要在同一行还是另起一行产生冲突。最后导致代码错误。
      • 解决方法
        • 关闭其中一种规则
        • 不使用plugin:vue/recommended,改用约束性较低的plugin:vue/essential规则
    • 我们发现我们还是更倾向于plugin:vue/recommended中定义的规则,所以我们决定在vue文件中不使用"plugin:prettier/recommended"规则来做格式化;在其他文件中调用prettier --write来格式化
1
2
3
{
"extends": ["plugin:vue/recommended","standard"]
}
  • 无论是直接启用vue-cli配置还是结合prettier使用,在我们项目中都有一些问题
    • 前者可以在bundle时自动lint,但没有使用prettier
    • 后者虽使用了prettier,却无法自动调用

使用 husky+lint-staged 改进

  • 关闭vue-cli自带的bundlelint的配置;在git commit之前自动做lint检查prettier格式化
  • husky和lint-staged的作用上面已经做过介绍,不做赘述,直接展示配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// package.json
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,vue}": [// 针对js、vue文件使用eslint --fix来做检查和格式化
"eslint --fix",
"git add"
],
"*.{json,css,scss,less,sass,md,html,flow,ts,tsd}": [ // 针对非js、vue文件使用pretter格式化
"prettier --write",
"git add"
]
}
  • 这样基本实现了,团队内部提交的代码风格一致,完成了预定目标
  • 但我们团队内部使用的都是vscode,大家不想在提交代码时再做检查和格式化;希望能在开发、保存时就能发现错误、格式化

VSCode 中实现自动提示错误,保存时自动格式化

  • 在上一步配置的基础上,再借助VSCode的ESLint、Prettier、Vetur扩展就可以完成此目标
    • 三个扩展的作用可以看文章前面的介绍
  • 我们希望针对js、vue文件,在保存时,自动发现低级错误并格式化;其它格式文件在保存时可以自动格式化
  1. 首先安装ESLint、Prettier、Vetur、Setting Sync扩展
  2. 配置ESLint扩展,开启保存时自动修复
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// settings.json
// * ------------------
// * eslint相关
// * ------------------
"eslint.enable": true,
"eslint.alwaysShowStatus": true, // 始终展示eslint状态
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true // 自动修复.vue文件的错误和完成格式化工作
}
],
"eslint.autoFixOnSave": true // 保存时自动修复
  1. 开启vscode的保存时自动格式化选项
1
2
3
4
5
// settings.json
// 保存时自动格式化。需要借助格式化器;
// 若此项为false,则所有格式化器(pretter插件)不能在保存时自动格式化;
// 通过npm包安装的格式化器如prettier、ESLint不受此项限制。
"editor.formatOnSave": true,
  1. vue文件中禁用pretter扩展
1
"prettier.disableLanguages": ["vue"],
  1. vue文件中禁用vetur的格式化选项
1
2
"vetur.format.defaultFormatter.html": "none",
"vetur.format.defaultFormatter.js": "none",
  • 完整settings.json配置如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
// * ------------------
// * 格式化相关
// * 主要思路:
// * .js和.vue文件使用eslint+eslint-plugin-vue配合autoFix来做代码检查和格式化;
// * .vue文件中禁用prettier和vetur对template和script部分的格式化
// * 其他类型文件如.css、.sass、.md等都使用prettier插件来格式化
// * ------------------
// 保存时自动格式化。需要借助格式化器;
// 若此项为false,则所有格式化器(pretter插件)不能在保存时自动格式化;
// 通过npm包安装的格式化器如prettier、ESLint不受此项限制。
"editor.formatOnSave": true,
// prettier插件配置
// 读取配置的优先级如下
// .prettierrc文件 > .editorconfig > prettier插件选项
"prettier.tabWidth": 2,
"prettier.singleQuote": true,
"prettier.semi": false,
// 在vue中使用eslint+eslint-plugin-vue并配合autoFix来做格式化,所以在vue中禁用prettier插件
"prettier.disableLanguages": ["vue"],
// vetur配置
// vetur中自带prettier格式化器,其也会读取项目中的.prettierrc配置文件
// 在.vue文件中将其禁用,使用eslint+eslint-plugin-vue配合autoFix来格式化;仅使用vetur中的prettier来格式化vue文件中的css部分
"vetur.format.defaultFormatter.html": "none",
"vetur.format.defaultFormatter.js": "none",
// * ------------------
// * eslint相关
// * ------------------
"eslint.enable": true,
"eslint.alwaysShowStatus": true, // 始终展示eslint状态
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true // 自动修复.vue文件的错误和完成格式化工作
}
],
"eslint.autoFixOnSave": true // 保存时自动修复
}
  • 问题
    • 上述配置是建立在使用了vue-cli创建项目,并且项目中存在eslint的配置文件时,如果项目中没有eslint配置文件,那么.vue文件将无法格式化。
      • 解决方法
        • 注释掉在.vue文件禁用prettier相关设置
1
2
3
// "prettier.disableLanguages": ["vue"],
// "vetur.format.defaultFormatter.html": "none",
// "vetur.format.defaultFormatter.js": "none",
  • PS: VSCode设置的共享,可以借助Settings Sync扩展来实现,具体方法可 google

参考