前期规范主要针对Vue2的历史项目,近期对Vue3项目的规则做了统一梳理,具体如…

系列文章:


前置背景

1.适用范围

主要针对:Vue3技术栈及相关生态的代码规则配置,其中 Node 版本大于18,且ESLint 版本大于8

package.json配置如下:

{
    "engines": {
        "node": ">=18"
    },
    "peerDependencies": {
        "eslint": "^8"
    }
}

2.Vue3项目创建

使用Vite初始化Vue3项目,更多参考 搭建Vite项目

# npm 7+, 需要额外加 --:
$ npm create vite@latest <project-name> -- --template vue-ts

一、配置ESLintTSPrettier

1. 依赖安装

这里介绍两种安装依赖的方式,第一种是参考给出的package.json进行配置安装,第二种是按照命令,依次安装配置。

1.1 按照package.json安装配置

参考以下package.json,在项目根目录执行:

$ npm i

package.json:

{
    "name": "vue3-ts-eslint-h5",
    "private": true,
    "version": "0.0.0",
    "type": "module",
    "scripts": {
        "dev": "vite",
        "build": "vue-tsc -b && vite build",
        "lint": "eslint --ext .js,.vue,.ts src",
        "lint:fix": "eslint --ext .js,.vue,.ts src --fix"
    },
    "engines": {
        "node": ">=18"
    },
    "peerDependencies": {
        "eslint": "^8"
    },
    "dependencies": {
        "vue": "^3.4.29",
        "vite": "^5.3.1",
    },
    "devDependencies": {
        "@typescript-eslint/eslint-plugin": "^7.14.1",
        "@typescript-eslint/parser": "^7.14.1",
        "@vitejs/plugin-vue": "^5.0.5", // 无关 - 可注释
        "@vue/eslint-config-standard": "^8.0.1",
        "@vue/eslint-config-typescript": "^13.0.0",
        "eslint": "8.56.0",
        "eslint-config-airbnb-base": "15.0.0", // js 相关
        "eslint-config-prettier": "9.1.0",
        "eslint-plugin-prettier": "5.1.3",
        "eslint-plugin-vue": "9.26.0",
        "eslint-plugin-import": "2.29.1", // eslint-config-airbnb-base 前置插件
        "prettier": "^3.3.2",
        "typescript": "^5.2.2",
        "vue-tsc": "^2.0.21", // 无关 - 可注释
        "lint-staged": "^9.1.0", // 无关 - git commit 检测eslint机制
    },
    "lint-staged": {
        "*.{js,ts,vue}": [
        "eslint --fix",
        "git add"
        ],
        "src/**/*.{vue,css,sass,scss}": [
        "stylelint --fix",
        "git add"
        ]
    },
    // 在.prettier配置,可代替此处配置
    "prettier": {
        // ...
    }
}

1.2 手动配置安装

手动添加ESLintTypeScript支持:

npm install --save-dev eslint eslint-plugin-vue typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin

npx install-peerdeps --dev eslint-config-airbnb-base
npm install --save-dev eslint-plugin-vue eslint-plugin-import

手动添加Prettier支持:

npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier

2. 配置ESLintTSPrettier

2.1 tsconfig.json 文件

确保项目根目录有tsconfig.json文件。以下是基本的TypeScript配置示例:

{
    "extends":"./other_tsconfig/tsconfig.json",
    "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "strict": true,
        "jsx": "preserve",
        "importHelpers": true,
        "moduleResolution": "node",
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "sourceMap": true,
        "baseUrl": ".",
        "paths": {
        "@/*": ["src/*"]
        },
        "lib": ["esnext", "dom"]
        // ---------------- 新增(待定)---------------
        
    },
    "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
    "exclude": ["node_modules"]
}

2.2 .prettierrc 文件

在项目根目录创建.prettierrc文件:

{
    "singleQuote": true,
    "tabWidth": 2,
    "semi": false,
    "eslintIntegration": true,
    "printWidth": 120,
    "endOfLine": "auto",
    "arrowParens": "always",
    "trailingComma": "none",
}

依赖.eslintrc.js中扩展Prettier配置:

// ...,
extends: [
  // ...
  'prettier',
],

2.3 .eslintrc.js 文件

在项目根目录下创建.eslintrc.js文件,并配置ESLint规则。以下是一个基本的配置示例:

module.exports = {
    root: true,
    env: {
        node: true,
        browser: true,
        es6: true,
    },
    globals: {},
    plugins: ['@typescript-eslint', 'vue'],
    extends: [
        'airbnb-base', // js
        'eslint:recommended', 
        '@vue/typescript/recommended', // 启用 Vue + TypeScript 推荐的 ESLint 配置
        'plugin:vue/vue3-recommended', // 启用 Vue 3 推荐的 ESLint 配置
        'plugin:prettier/recommended', // 确保 Prettier 格式化的代码不被 ESLint 覆盖
        'prettier',
    ],
    ignorePatterns: ['.eslintrc.js'],
    parser: 'vue-eslint-parser', // 使用 Vue 专用的解析器以便解析 .vue 文件
    parserOptions: {
        parser: '@typescript-eslint/parser', // 使用 TypeScript 解析器解析 .ts 和 .tsx 文件
        extraFileExtensions: ['.vue'], 
        project: './tsconfig.json' 
        ecmaVersion: 2020, // 支持 ECMAScript 2020 的语法块
        sourceType: 'module', // 代码使用 ES 模块
        // ecmaFeatures: { // 允许在代码中使用 JSX
        //   jsx: true,
        // },
    },
    rules: {
        // ------------------ 公共 ------------------
        'prettier/prettier': ['warn'],
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        '@typescript-eslint/no-explicit-any': 'off',
        'import/no-extraneous-dependencies': 'off',
        // ------------------ 新增 js ------------------
        // non stylistic rules which are conflict with airbnb-base
        'no-empty': ['warn', { allowEmptyCatch: true }],
        'no-unused-vars': ['warn', { args: 'none' }],
        'arrow-body-style': ['off'],
        'import/first': 'off', // 防止出现首行报红问题
        'no-use-before-define': 'off',
        'complexity': ['warn', { max: 10 }], // 配置 eslint 的 complexity
        // ------------------ 新增 ts ------------------
        '@typescript-eslint/unbound-method': ['off'], // 在 vue 项目中 不用担心 this 丢失问题,包括 .vue, mixins
        '@typescript-eslint/no-use-before-define': ['error'], // 你不能在定义变量、函数、类等之前使用它们
        '@typescript-eslint/no-unused-vars': 'off', // 关闭此规则,避免对未使用的变量发出警告
        // '@typescript-eslint/no-explicit-any': 'error', // 不允许使用any类型
    复杂度约束每个函数的最大if分支数
        // ------------------ 新增 vue3 ------------------
        'vue/multi-word-component-names': 'off', // 避免与 HTML 原生元素名称冲突
        'vue/script-setup-uses-vars': 'error', // 确保 script setup 中的变量在 template 中被正确识别
    },
    overrides: [
        {
            files: ['*.vue'],
            rules: {
                'vue/require-direct-export': ['off'],
            },
        },
        {
            files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)']
        }
    ]
};

二、常见ESLint规则校验失败类型

常见ESLint规则校验失败类型,主要分为两类: 可自动修复的和需手动修复的

1. 可自动修复的

$ npm run lint # 检测
$ npm run lint:fix # 修复

2. 需手动修复的

主要包括:

  • TS类型规范和参数规范
  • 包的导入规范
  • 变量命名
// camelcase 推荐使用 camelCase 来命名变量和函数
// 示例:将 oa_nextNodeAssignee 重命名为 oaNextNodeAssignee 或其他符合 camelCase 约定的名称

//  no-new
// 用了 new 关键字来创建一个对象,但这个对象没有被赋值给任何变量,也没有被用作表达式的一部分。
// 这通常被视为一种不良实践,因为它可能导致不必要的资源分配或难以跟踪的副作用

// complexity -  warning  某个函数的中的决策点(如if语句、for循环、while循环、case语句等)
// 复杂程度过高
// 详细错误示例:warning  Arrow function has a complexity of 13. Maximum allowed is 10  complexity
// eslint-disable-next-line complexity  
const myComplexFunction = () => {  
  // ... function body  
};


// no-underscore-dangle 
// 禁止在变量名中使用前导或尾随下划线(除了 _、__proto__、constructor、Object.prototype 的属性或方法外)

// no-useless-escape 正则表达式中不必要的转义字符的错误

// prefer-regex-literals 规则推荐使用正则表达式字面量来替代 RegExp 构造函数
// 如:你的代码是 new RegExp('\\d+'),可以替换为 /\d+/

// prefer-promise-reject-errors 将 Promise 的拒绝原因改为 Error 对象

// no-async-promise-executor 错误发生在尝试将 async 关键字用于 Promise 的执行函数(executor function)中时
// bad
const validateTaxCode = (value: any) =>
    new Promise(async (resolve) => {
        const res = await checkLastSubject({
        subjectCode: value
        })
        resolve(res)
    })
}
// good
const validateTaxCode = (value: any) =>
    new Promise((resolve) => {
        const res = await checkLastSubject({
        subjectCode: value
        })
        resolve(res)
    })
}


// 严格等于 eqeqeq 
// ESLint 建议使用 === 而不是 ==,因为 === 会比较值和类型,而 == 会在比较前尝试进行类型转换,这可能会导致意外的结果

// 重复导入 import/no-duplicates
// bad 
import { defineRuntimeHooks } from '@zto/zmi'
import { getEnv } from '@zto/zmi'

// good
import { defineRuntimeHooks, getEnv } from '@zto/zmi'

// TS类型错误
// @typescript-eslint/no-unused-vars // 定义了一个名为 xxx 的变量或导入,但它在代码中从未被使用过
// @typescript-eslint/no-unsafe-argument // 没有为变量或属性提供明确的类型,或者从某些函数/方法中获取了未明确指定类型的值时
// @typescript-eslint/no-use-before-define // 表明你在使用 xxx 方法前没有先定义它
// @typescript-eslint/no-unsafe-enum-comparison // 枚举(enum)类型和你的判断条件不匹配

三、常见配置问题

1. 当前版本为Node 16,如何对以上eslint相关包降级处理?

package.json配置要求如下:

{
    "engines": {
        "node": ">=16"
    },
    "peerDependencies": {
        "eslint": "^7.2.0 || ^8"
    },
}

首先,是ESLint相关的包,因为要求Node 版本大于18,所以进行降级

{
    "@typescript-eslint/eslint-plugin": "7.14.1",  // 7.2.0
    "@typescript-eslint/parser": "7.14.1", // 7.2.0
    "@vue/eslint-config-typescript": "13.0.0" // 12.0.0
}

其次,执行npm run lint,报错如下:

$ npm run lint
> zmi-test@1.0.3 lint
> eslint --ext .js,.vue,.ts src

=============

WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.

You may find that it works just fine, or you may not.

SUPPORTED TYPESCRIPT VERSIONS: >=4.7.4 <5.5.0
YOUR TYPESCRIPT VERSION: 5.5.2

Please only submit bug reports when using the officially supported version.
=============

@typescript-eslint/parser 包的依赖 @typescript-eslint/typescript-estree, 其前置依赖的typescript有版本要求,需要降级处理

{
    "typescript": "5.5.2" // 降级 4.7.4
}

综上,最终降级后的包版本如下:

{
    "@typescript-eslint/eslint-plugin": "7.2.0",
    "@typescript-eslint/parser": "7.2.0",
    "@vue/eslint-config-typescript": "12.0.0",
    "typescript": "4.7.4"
}

参考


最后, 希望大家早日实现:成为编程高手的伟大梦想!
欢迎交流~

微信公众号

本文版权归原作者曜灵所有!未经允许,严禁转载!对非法转载者, 原作者保留采用法律手段追究的权利!
若需转载,请联系微信公众号:连先生有猫病,可获取作者联系方式!