阅读 1246

Vue + TypeScript 项目放弃 TSLint,拥抱 ESLint

背景

我们有一些项目用了 TSLint 来规范我们的 TypeScript 代码,有的甚至没有 Lint 工具来辅助开发,由于性能问题,我们这里采用 ESLint 来取代 TSLint,并结合 prettier 和钩子工具来规范我们的代码和统一团队开发风格。


一、安装 ESLint,删除 TSLint

由于我们的项目配置可能不大一样,有的是 vue-cli 自带安装的 ESLint 或者 TSLint,有的项目没有 Lint 工具。给大家参考下 package.json

PS:这里有一个小坑,eslint 版本问题导致的 bug,所以 eslint 限制了版本号在 6.5.1

<!-- package.json 相关配置 -->
{
  "scripts": {
    "format": "prettier --write \"src/**/*.ts\" \"src/**/*.vue\"",
    "lint": "eslint --fix --ext .ts,.vue src"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/**/*.{ts,vue}": [
      "prettier --write",
      "eslint --fix"
    ]
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^2.21.0",
    "@typescript-eslint/parser": "^2.20.0",
    "eslint": "^6.5.1",
    "eslint-config-prettier": "^6.10.0",
    "eslint-plugin-prettier": "^3.1.2",
    "eslint-plugin-vue": "^5.2.3",
    "husky": "^4.2.3",
    "lint-staged": "^10.0.7",
    "prettier": "^1.19.1",
    "vue-eslint-parser": "^7.0.0",
  }
}
复制代码
  • 1、首先删除 tslint.json 配置文件

  • 2、安装 eslint 相关依赖

    npm i -D eslint@6.5.1 @typescript-eslint/parser @typescript-eslint/eslint-plugin

    @typescript-eslint/parser: ESLint 专门解析 TypeScript 的解析器
    @typescript-eslint/eslint-plugin: 内置各种解析 TypeScript rules 插件

  • 3、新建 .eslintrc.js 文件

  parser: 'vue-eslint-parser', // 解析 .vue 文件
  extends: [
    'plugin:@typescript-eslint/recommended',
  ],
  plugins: ['@typescript-eslint'],
  parserOptions: {
    parser: '@typescript-eslint/parser' // 解析 .ts 文件
  },
复制代码

注意: parser: 'vue-eslint-parser',这里要区分和 parserOptions.parser 的区别,vue-eslint-parser 是解析 .vue 文件,而 parserOptions.parser:@typescript-eslint/parser 是我们自定义来解析 TypeScript 文件的,否则就无法正确的检验 TypeScript 相关内容

二、安装 eslint-plugin-vue

eslint-plugin-vue 插件是用来检测和规范 Vue 代码的风格

npm i -D eslint-plugin-vue

然后在 .eslintrc.js 新增配置和相关规则

extends: [
  'plugin:vue/recommended', // 这里也可以启用其他规则,如默认的 vue/essential
  'plugin:@typescript-eslint/recommended',
],
rules: {
    ...
}
复制代码

三、安装 prettier

prettier 用来做格式化工具配合我们的 ESLint 可以更大的发挥作用,首先安装相关依赖:

npm i -D prettier eslint-config-prettier eslint-plugin-prettier
复制代码

eslint-config-prettier: 这个插件的作用是当 ESLint 和 prettier 配置冲突时优先 prettier
eslint-plugin-prettier: 将 prettier 作为 ESLint 规范来使用

extends: [
  'plugin:vue/recommended',
  'plugin:prettier/recommended', 
  'prettier/@typescript-eslint', // 优先 prettier 中的样式规范
  'plugin:@typescript-eslint/recommended',
],
复制代码

接着按需配置 prettier,新建 .prettierrc 文件

{
  "singleQuote": true,
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "trailingComma": "all",
  "printWidth": 120
}
复制代码

整个 .eslintrc.js 如下

module.exports = {
  root: true,
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  parser: 'vue-eslint-parser',
  extends: [
    'plugin:vue/recommended',
    'plugin:prettier/recommended',
    'prettier/@typescript-eslint',
    'plugin:@typescript-eslint/recommended',
  ],
  plugins: ['@typescript-eslint'],
  parserOptions: {
    parser: '@typescript-eslint/parser',
  },
  rules: {
    'prettier/prettier': 'error',
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'array-bracket-spacing': 2,
    'no-var': 2,
    'no-eval': 2,
    'arrow-spacing': 2,
    'block-spacing': 2,
    'key-spacing': 2,
    'brace-style': 2,
    'vue/camelcase': 2,
    'vue/require-component-is': 0,
    'vue/require-default-prop': 0,
    'comma-dangle': [2, 'always-multiline'],
    'vue/eqeqeq': [2, 'always', { null: 'ignore' }],
    'object-curly-spacing': [2, 'always'],
    'vue/singleline-html-element-content-newline': 0,
    'vue/html-closing-bracket-newline': [
      2,
      {
        singleline: 'never',
        multiline: 'always',
      },
    ],
    'vue/max-attributes-per-line': 0,
    'vue/html-self-closing': [
      2,
      {
        html: {
          void: 'always',
          normal: 'never',
          component: 'always',
        },
        svg: 'always',
        math: 'always',
      },
    ],

    // 设置 typescript-eslint 规则
    // https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/docs/rules
    '@typescript-eslint/camelcase': 0, // 目前埋点有部分字段无法更换
    '@typescript-eslint/no-non-null-assertion': 0, // 允许非空断言运算符
    '@typescript-eslint/member-delimiter-style': [
      2,
      {
        multiline: {
          delimiter: 'none',
          requireLast: true,
        },
        singleline: {
          delimiter: 'semi',
          requireLast: false,
        },
      },
    ],
    '@typescript-eslint/no-unused-vars': [0, { args: 'none' }], // TODO 后期逐步替换
    '@typescript-eslint/interface-name-prefix': 0,
    '@typescript-eslint/explicit-function-return-type': 0,
    '@typescript-eslint/no-empty-function': 0,
    '@typescript-eslint/no-var-requires': 0,
    '@typescript-eslint/no-use-before-define': 0,
    '@typescript-eslint/no-explicit-any': 0, // TODO
  },
}
复制代码

到这里 ESLint 和 prettier 相关配置已经完成,接下来我们利用一些工具帮我们在 git commit 阶段完成代码格式化和校验工作。

四、使用 husky 和 lint-staged 钩子完成校验与格式化

  • husky 是控制代码提交的钩子,在代码被提交到Git仓库之前,我们可以在这里做一些预检查或者格式化工作。
  • lint-staged 是一个前端文件过滤的工具(仅仅是文件过滤器),可以对文件系统进行过滤,使得每次提交不必对所有文件进行校验

1. 安装husky 和 lint-staged

npm i -D husky lint-staged
复制代码

2. 修改 package.json,增加配置:

"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
 },
"lint-staged": {
   "src/**/*.{ts,vue}": [
      "prettier --write",
      "eslint --fix"
   ]
},
复制代码

上面配置,每次它只会在你本地 commit 之前,校验你提交的内容是否符合你本地配置的 eslint规则,如果符合规则,则会提交成功。如果不符合它会自动执行 eslint —fix 尝试帮你自动修复,如果修复成功则会帮你把修复好的代码提交,如果失败,则会提示你错误,让你修好这个错误之后才能允许你提交代码。

五、Vscode 相关配置

  • 安装 ESLint, Vertur, Prettier 插件,如果你用 stylus 建议装一个 Manta's Stylus Supremacy
  • 配置 setting.json
{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "vetur.format.defaultFormatter.ts": "prettier",
  "vetur.format.defaultFormatter.js": "prettier",
  "vetur.format.defaultFormatter.less": "prettier",
  "vetur.format.defaultFormatter.stylus": "stylus-supremacy",
  "vetur.format.defaultFormatter.html": "prettyhtml",
  "vetur.format.defaultFormatterOptions": {
    "prettyhtml": {
      "printWidth": 120
    }
  },
  "eslint.options": {
    "extensions": [
      ".js",
      ".vue",
      ".ts",
      ".tsx"
    ]
  },
  // 以下为 stylus 配置
  "stylusSupremacy.insertColons": false, // 是否插入冒号
  "stylusSupremacy.insertSemicolons": false, // 是否插入分好
  "stylusSupremacy.insertBraces": false, // 是否插入大括号
  "stylusSupremacy.insertNewLineAroundImports": false, // import之后是否换行
  "stylusSupremacy.insertNewLineAroundBlocks": false
}
复制代码

setting.json 可以直接复制在本地,也可以在项目中新建一个 .vscode 文件夹,然后在 .gitignore 中把 .vscode 去掉,这样团队都可以共享这部分 vscode 配置。

总结

通过以上几步我们可以在 git commit 之前自动帮我们完成格式化和校验的工作,但是值得注意的是,这里的格式化和校验并不是全局的,而是我们当前提交的内容,如果我们想要格式化全局代码或者校验全局代码,这里我们可以在 package.json 中的 script 写个钩子需要的时候手动执行一下,而不是把它放在 pre-commit 钩子上每次 git commit 都执行,耗费时间。

"scripts": {
  "format": "prettier --write \"src/**/*.ts\" \"src/**/*.vue\"",
  "lint": "eslint --fix --ext .ts,.vue src"
}
复制代码

另外各种插件因为版本问题导致的冲突一般都可以在对应插件的 github issues 中找到答案。