一 添加ESLint+Prettier代码校验与格式化功能
1.1 安装ESLint和Prettier相关npm工具包
bash
pnpm add -D eslint jiti eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y @typescript-eslint/eslint-plugin @typescript-eslint/parser @eslint/js @types/eslint-plugin-jsx-a11y globals
pnpm add -D prettier eslint-config-prettier eslint-plugin-prettier
这些包的用途如下:
npm包名 | 用途 |
---|---|
eslint-plugin-react-hooks | 提供 React Hooks 相关的 ESLint 插件,确保符合 React Hooks 的最佳实践。 |
eslint-plugin-react | 提供 React 相关的 ESLint 插件,包含 React 特有的最佳实践和规则 |
@typescript-eslint/parser | 允许 ESLint 解析 TypeScript 代码,并为 ESLint 提供语法分析功能。 |
@typescript-eslint/eslint-plugin | 是 TypeScript 的 ESLint 插件,提供了一些 TypeScript 特有的规则。 |
@eslint/js | 是 ESLint 官方的 JavaScript 规则集,提供了一些基础的 JavaScript 规则 |
jiti | jiti 允许你使用 eslint.config.js 这样的 ESM 格式配置文件,而不是传统的 .eslintrc.js 。主要用于支持 flat config(ESLint 9+ 采用的新配置方式) |
eslint-plugin-jsx-a11y | Airbnb主要维护,JSX 无障碍性社区贡献和支持 |
eslint-config-prettier | 用于关闭 ESLint 规则中与 Prettier 冲突的格式化规则,避免 ESLint 和 Prettier 冲突 |
eslint-plugin-prettier | 把 Prettier 作为 ESLint 规则,让 ESLint 直接检查 Prettier 规则 |
配置 eslint.config.ts
ESLint9和ESLint9之间的版本配置不太一样,最大的变化是配置内容由对象格式变成了扁平数组结构:
ts
import js from '@eslint/js';
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import prettierPlugin from 'eslint-plugin-prettier';
export default [
js.configs.recommended, // JavaScript 推荐规则
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: tsParser,
parserOptions: {
project: './tsconfig.json',
ecmaVersion: 2020,
sourceType: 'module',
},
},
plugins: {
'@typescript-eslint': tsPlugin, // 使用已导入的插件对象
react: reactPlugin, // 使用已导入的插件对象
'react-hooks': reactHooksPlugin, // 使用已导入的插件对象
prettier: prettierPlugin, // 使用已导入的插件对象
},
rules: {
'react/prop-types': 'off', // TypeScript 不需要 PropTypes
'@typescript-eslint/no-explicit-any': 'error', // 禁止使用 any
'@typescript-eslint/explicit-function-return-type': 'warn', // 要求显式返回类型
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // 忽略未使用变量
'@typescript-eslint/no-non-null-assertion': 'warn', // 避免不安全的非空断言
'prettier/prettier': 'error', // 启用 Prettier 规则
},
},
{
ignores: [
'node_modules/', // 忽略 node_modules
'dist/', // 忽略构建产物
'build/', // 忽略构建目录
'public/', // 忽略静态资源
'**/*.min.js', // 忽略压缩 JS
'**/vendor/**', // 忽略第三方库
'coverage/', // 忽略测试覆盖率报告
],
},
];
配置.prettierrc
js
{
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "avoid",
"endOfLine": "lf",
"jsxSingleQuote": false,
"trailingComma": "es5",
"embeddedLanguageFormatting": "auto"
}
各项属性的含义:
prettier属性 | 用途说明 |
---|---|
embeddedLanguageFormatting | 'auto' :自动格式化嵌套代码(默认设置) const element = <div>{myFunction()}</div>; 'off' :禁止嵌套代码的格式化 'on' :始终格式化嵌套代码 |
endOfLine | 'lf' :使用 Linux/Mac 风格的行尾符(Line Feed,LF ) 'crlf' :使用 Windows 风格的行尾符(Carriage Return + Line Feed,CRLF ) 'auto' :根据操作系统自动选择合适的行尾符 |
arrowParens | 'always' :无论参数是一个还是多个,都强制添加括号。例如:(x) => x + 1 'avoid' :如果只有一个参数,且没有箭头函数体括号,可以省略括号。例如:x => x + 1 |
jsxBracketSameLine | false 表示 > 会放在新的一行,而 true 会将 > 放在行尾。这通常影响多行 JSX 元素的格式。 |
bracketSpacing | true 表示在对象字面量的大括号 {} 内添加空格,如 { foo: bar } ;false 则不添加空格,如 {foo: bar} 。 |
trailingComma | 'es5' :在 ES5 中有效的地方添加尾逗号,比如对象和数组的最后一个元素。 'all' :在所有可能的地方添加尾逗号(包括函数参数) 'none' :不添加尾逗号 |
jsxSingleQuote | false 表示在 JSX 属性值中使用双引号(默认行为),true 表示使用单引号 |
quoteProps | 'as-needed' :仅当属性名是 JavaScript 保留字或者包含空格等特殊字符时,才会加引号。 'consistent' :如果对象中的某个属性加了引号,则其他所有属性也都会加引号。 'preserve' :保持现有的引号使用。 |
singleQuote | true 表示在字符串中使用单引号,而 false 则使用双引号 |
semi | 是否在语句末尾添加分号 |
useTabs | 是否使用制表符(tab)代替空格进行缩进 |
tabWidth | 设置每个缩进级别的空格数 |
printWidth | 指定代码的最大行宽。Prettier 会在达到指定宽度后自动换行,避免过长的行 |
配置 .prettierignore 有些文件夹及文件不需要格式化,要进行忽略
js
dist
coverage
html
public
node_modules
*.yaml
pnpm-lock.yaml
在package.json中配置指令
js
"scripts": {
"code:check": "eslint src --ext .ts,.tsx",
"code:fix": "eslint src --ext .ts,.tsx --fix",
"format:fix": "prettier --write ./",
"format:check": "prettier --check ./",
}
1.2 在VSCode中安装ESLint和Prettier
在扩展面板搜索ESLint
和Prettier - Code formatter
.vscode\extension.json文件内容
推荐扩展配置
json
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"streetsidesoftware.code-spell-checker",
"foxundermoon.shell-format"
]
}
.vscode\settings.json文件内容
配置保存文件时运行ESLint和Prettier配置规则
json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
}
1.3 报错处理
4. @typescript-eslint/typescript-estree与ypescript版本不匹配
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: >=3.3.1 <4.5.0
YOUR TYPESCRIPT VERSION: 4.9.5
Please only submit bug reports when using the officially supported version.
这个问题较严重,所以恢复到没修改之前的package.json和pnpm-lock.yaml版本,删除node_modules,重新安装依赖。
3. 找不到模块"@typescript-eslint/parser"或其相应的类型声明。
"d:/project/avatar-front-end-h5/node_modules/@typescript-eslint/parser/dist/index.d.ts"处有类型,但无法在当前 "moduleResolution" 设置下解析此结果。请考虑更新到 "node16"、"nodenext" 或 "bundler"。ts(2307) 这个错误通常是由于 TypeScript 的 moduleResolution
选项设置不正确,导致无法解析 @typescript-eslint/parser
模块。以下是几个可能的解决方案:
json
{
"compilerOptions": {
"moduleResolution": "node16"
}
}
2. Parsing error: ESLint was configured to run on <tsconfigRootDir>/eslint.config.ts using parserOptions.project: <tsconfigRootDir>/tsconfig.json
ESLint 在解析 eslint.config.ts
时遇到了问题,可能的原因是 parserOptions.project
指向的 tsconfig.json
配置不兼容。tsconfig.json的include
选项缺少 对eslint.config.ts的包含
js
{
"include": ["src", "eslint.config.ts"]
}
1. A config object has a "plugins" key defined as an array of strings
Oops! Something went wrong! :(
ESLint: 9.23.0
A config object has a "plugins" key defined as an array of strings. It looks something like this:
json
{
"plugins": ["react-hooks"]
}
Flat config requires "plugins" to be an object, like this:
css
{
plugins: {
react-hooks: pluginObject
}
}
不是plugins部分本身配置的不是对象, 而是由于 react.configs.recommended
配置不符合ESLint9的配置语法,注释掉
js
{
{
plugins: {
'@typescript-eslint': ts, // 使用已导入的插件对象
react: react, // 使用已导入的插件对象
'react-hooks': reactHooks, // 使用已导入的插件对象
prettier: prettier, // 使用已导入的插件对象
},
},
// react.configs.recommended, // React 推荐规则
}
二 扫描出的常见问题
2.1 告警类型
19. Arrow function has too many lines (52). Maximum allowed is 50 函数行数超过50行
18../components/Subway
import should occur after import of @/utils/date-format
'import/order' 导入顺序不对,此条规则可关闭。
17.Unexpected use of 'location' 在 JavaScript 中,location
是浏览器环境中的一个全局变量。如果你在一个非浏览器的环境中(例如 Node.js)使用它,或者在代码中不小心使用了 location
,ESLint 会认为不小心引用了全局的 location
对象。此条规则可关闭
js
await setQrUrl(location.href.includes('?isQrcode') ? location.href : location.href + '?isQrcode');
16.React Hook useMemo has missing dependencies: 'activeDay', 'id', 'locat.search', and 'navi'. Either include them or remove the dependency array. Mutable values like 'startDate.current' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
在 useMemo
钩子中,依赖项数组缺少了一些应该作为依赖项的变量。关闭此条规则
js
// bad
const result = useMemo(() => {
// 使用了 activeDay, id, locat.search 和 navi,但没有在依赖项数组中列出它们
return someCalculation(activeDay, id, locat.search, navi);
}, []); // 这里的依赖项数组为空,应该包含 activeDay, id, locat.search, navi
// good
const result = useMemo(() => {
// 使用了 activeDay, id, locat.search 和 navi
return someCalculation(activeDay, id, locat.search, navi);
}, [activeDay, id, locat.search, navi]); // 将它们列为依赖项
15.React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked
在 useEffect
的依赖数组中使用了复杂的表达式,导致 React 无法静态分析这个依赖项是否会改变。
js
// bad
const MyComponent = () => {
const [counter, setCounter] = useState(0);
const [someArray, setSomeArray] = useState([1, 2, 3]);
useEffect(() => {
console.log('Effect triggered');
}, [someArray.filter(item => item > 1)]); // 复杂的表达式作为依赖项
};
// good
const MyComponent = () => {
const [counter, setCounter] = useState(0);
const [someArray, setSomeArray] = useState([1, 2, 3]);
const filteredArray = someArray.filter(item => item > 1); // 提取复杂表达式到一个变量
useEffect(() => {
console.log('Effect triggered');
}, [filteredArray]); // 使用提取后的变量作为依赖项
};
14. React Hook useEffect has a missing dependency: 'getPlaceData'. Either include it or remove the dependency array
React 的 useEffect
Hook 会根据依赖数组中的变量来决定是否重新执行该副作用函数。如果副作用函数使用了某些外部变量(比如 getPlaceData
),但是没有将这些变量添加到依赖数组中,React 无法确定这些变量的变化是否应该触发副作用的重新执行。关闭此条规则
js
const [places, setPlaces] = useState([]);
const getPlaceData = () => {
// 假设这是一个获取地点数据的函数
fetch('/api/places')
.then(response => response.json())
.then(data => setPlaces(data));
};
// bad
useEffect(() => {
getPlaceData(); // 这个函数在 useEffect 中被调用
}, []); // 依赖数组为空,意味着 useEffect 只在组件挂载时执行一次
// good
useEffect(() => {
getPlaceData();
}, [getPlaceData]);
13. warning Expected '===' and instead saw '==' eqeqeq, 要使用恒等表达式
12. Unexpected console statement 不允许使用console, 关闭该规则
11. '@/pages/chat' imported multiple times 重复导入
js
import Chat from '@/pages/chat';
import Schedule from '@/pages/schedule';
import ChatPage from '@/pages/chat';
10. Expected an assignment or function call and instead saw an expression
ESLint 认为下面这两种写法是表达式但没有进行任何操作,尤其是在没有直接返回结果或赋值的情况下。 ,这是正常用法,关闭该规则。
js
// 情况一
errorMsg && message.error(errorMsg);
// 情况二
type === 'train' ? (visible.value = true) : (deployVisible.value = true);
9.Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free @typescript-eslint/ban-ts-comment
设置@ts-ignore就是为了忽略下方一行,如果因此产生警告,不太合理。所以关闭这条规则。
8. 'selectOptions' is defined but never used. Allowed unused args must match /^_/u
未使用的变量警告,可以删除或将selectOptions改为_selectOptions
, 这样eslint就不会检查了
js
const cascaderchange = (value: ValueType, selectoptions: DefaultoptionType[]|DefaultoptionType[][])=>{
emits('cascaderchange',value);
}
7. Prop 'value' requires default value to be set在 defineProps
或 props
里定义了 value
但未提供默认值, 关闭此条规则
js
// bad
interface IProps {
value?: Record<string, any>;
}
// good
interface IProps {
value?: Record<string, any> | undefined;
}
6. Prop "upstep_val","content_class" is not in camelCase 变量应该使用小驼峰
5. 'v-html' directive can lead to XSS attack 不允许使用v-html 关闭此条规则
4. Forbidden non-null assertion @typescript-eslint/no-non-null-assertion
禁止使用 非空断言 (!
),即在变量或表达式后加上 !
,表示该值不可能是 null
或 undefined
。 关闭规则
3.Anchor used as a button. Anchors are primarily expected to navigate. Use the button element instead.
<a>
标签应该用于导航,而不是作为按钮使用 。如果 <a>
不是用于跳转,而是用于触发某些操作(如 onClick
),应该改用 <button>
。 关闭规则
2. warning img elements must have an alt prop, either with meaningful text, or an empty string for decorative images
所有 img
元素必须有 alt
属性 ,该属性应该包含描述图像内容的文本,如果图像只是装饰性用途,则 alt
属性应为空字符串 ""
。
1.Missing return type on function 需要在ts中指明函数返回类型
2.2 错误类型
10. Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive
v-bind:key
应该使用在 v-for
中定义的变量来确保每个元素的唯一性和高效的渲染
js
// bad
<a-select-option v-for="opt in item.option" :key="item.value" :value="opt.value">{{opt.label}}</a-select-option>
// good
<a-select-option v-for="opt in item.option" :key="opt.value" :value="opt.value">{{opt.label}}</a-select-option>
9. The {}
("empty object") type allows any non-nullish value, including literals like 0
and ""
.
在 TypeScript 中,使用 {}
作为类型意味着 "任何非 null
或 undefined
的值",这包括所有原始类型(例如 0
、""
、false
等)。这意味着 {}
并不严格限制为对象类型。
js
// bad
interface IProps {
closeVisible: () => {};
}
// good
interface IProps {
closeVisible: () => void;
}
8. 'url' is never reassigned. Use 'const' instead ,不会再被赋值的变量,应该用const声明
7. Component name "index" should always be multi-word vue文件的命名必须是多个单词,关闭掉
6. 第三方字体包src\assets\font\iconfont.js检测出问题 忽略对第三方字体文件的检查
5. 将生成到 CommonJS 输出的文件中不允许 'import.meta' 元属性。解决方法:
将 TypeScript 配置为生成 ES Module
js
{
"compilerOptions": {
"module": "ESNext", // 或 "ESModule"
"moduleResolution": "Node"
}
}
4. Empty block statement 空的声明块
3.Unexpected any. Specify a different type ts 必须定义具体的类型,高频且改起来比较费劲的问题
2. xxx is defined but never used,'pushLastMessage' is assigned a value but never used 变量定义了未使用,高频错误
1. 'console','setTimeout','setInterval','clearInterval', 'NodeJS', 'React' is not defined
ESLint 认为 console
、setTimeout
、setInterval
等全局变量未定义。这通常是因为 ESLint 没有正确识别 JavaScript 运行环境(如浏览器或 Node.js)。
解决方法:
js
pnpm add -D globals
在eslint.config.ts添加如下配置
ts
import globals from 'globals';
export default [
{
languageOptions: {
// ...
globals: {
...globals.serviceworker,
...globals.browser,
...globals.node,
...globals.es2021,
},
},
}
]