20250609 eslint V8

This commit is contained in:
mac·ufutx 2025-06-09 17:10:41 +08:00
parent be53ff00c0
commit 3d9f87d02b
11 changed files with 179 additions and 132 deletions

View File

@ -5,3 +5,9 @@ public
*.d.ts
.vscode
.husky
# 忽略目录
coverage/
# 忽略文件
*.d.ts
*.log

View File

@ -1,60 +1,59 @@
// .eslintrc.cjs
const path = require('path')
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
es6: true
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended', // Vue 3 推荐规则
'@vue/eslint-config-typescript', // TypeScript 支持
'prettier', // 关闭与 Prettier 冲突的规则(需先安装 prettier
'plugin:prettier/recommended', // 将 Prettier 规则作为 ESLint 规则
'plugin:vue/vue3-recommended', // 加载 Vue 3 推荐规则
'@vue/eslint-config-typescript', // 加载 TypeScript 支持
'plugin:prettier/recommended' // 确保放在最后
],
parser: 'vue-eslint-parser', // 解析 Vue 模板
parserOptions: {
parser: '@typescript-eslint/parser', // 解析 TypeScript 代码
project: path.resolve(__dirname, 'tsconfig.app.json'), // 使用正确的 TSConfig
tsconfigRootDir: __dirname,
ecmaVersion: 'latest',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
sourceType: 'module'
},
plugins: ['vue', 'prettier', '@typescript-eslint'], // 显式注册所有插件
rules: {
// 自定义规则(根据团队需求调整)
'vue/multi-word-component-names': 'off',
'prettier/prettier': 'error', // 将 Prettier 错误视为 ESLint 错误
// 强制使用 === 而非 ==
'eqeqeq': 'error',
'vue/no-undef-components': 'error',
// 针对非 Vue 文件禁用 Vue 规则
// 'vue/no-unregistered-components': [
// 'error',
// { ignorePatterns: ['^router$', '^store$'] } // 可选:忽略特定组件名称
// ],
'vue/multi-word-component-names': [
'error',
{
ignores: ['Test'] // 可选:忽略特定组件名
}
],
// 组件 props 必须有类型和默认值
'vue/require-default-prop': 'error',
'vue/require-prop-types': 'error',
// 限制每行最大长度
'max-len': ['warn', {code: 120}],
// 禁止使用未定义的组件
'vue/no-unregistered-components': 'error',
// 组件名必须为 PascalCase
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
// 禁止使用 v-html防止 XSS
'vue/no-v-html': 'warn',
// 自定义规则(根据团队需求调整)
'vue/multi-word-component-names': 'off', // 允许单字组件名
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'@typescript-eslint/no-unused-vars': ['warn', {argsIgnorePattern: '^_'}],
// 其他自定义规则
'prettier/prettier': 'error',
'@typescript-eslint/no-unused-vars': 'warn',
'max-len': 'off'
},
overrides: [
// 针对测试文件的规则
// {
// files: ['*.vue'], // 仅对 Vue 文件应用 Vue 规则
// rules: {
// 'vue/no-unregistered-components': 'error'
// }
// },
{
files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'],
env: {
jest: true,
},
},
],
files: ['*.ts', '*.js'], // 非 Vue 文件不应用 Vue 规则
rules: {
'vue/no-unregistered-components': 'off'
}
}
]
}

View File

@ -1,5 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm test
npx lint-staged

View File

@ -26,21 +26,23 @@
},
"devDependencies": {
"@types/axios": "^0.9.36",
"@typescript-eslint/eslint-plugin": "^8.33.1",
"@typescript-eslint/parser": "^8.33.1",
"@typescript-eslint/eslint-plugin": "5.62.0",
"@typescript-eslint/parser": "5.62.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vue/eslint-config-typescript": "^14.5.0",
"@vue/eslint-config-typescript": "12.0.0",
"@vue/tsconfig": "^0.7.0",
"autoprefixer": "^10.4.14",
"eslint": "^9.28.0",
"eslint-plugin-vue": "^10.2.0",
"eslint": "8.57.1",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.0.0",
"husky": "^8.0.0",
"less": "^4.3.0",
"less-loader": "^12.3.0",
"lint-staged": "^16.1.0",
"postcss": "^8.4.24",
"prettier": "^3.5.3",
"typescript": "~5.8.3",
"typescript": "5.1.6",
"vite": "^4.4.9",
"vite-plugin-image-optimizer": "^1.1.8",
"vue-tsc": "^2.2.8"

View File

@ -4,6 +4,7 @@ import HelloWorld from './components/HelloWorld.vue'
<template>
<div>
<!-- <NonExistentComponent />-->
<a href="https://vite.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
@ -21,9 +22,11 @@ import HelloWorld from './components/HelloWorld.vue'
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}

View File

@ -1 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img"
class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198">
<path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path>
<path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path>
<path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 496 B

After

Width:  |  Height:  |  Size: 517 B

View File

@ -22,12 +22,12 @@ const fetchData = async () => {
data.value = res
// 2. GET
const params = { page: 1, limit: 10 }
const paginatedData = await request.get('/api/users', params)
// const params = { page: 1, limit: 10 }
// const paginatedData = await request.get('/api/users', params)
// 3.
const config = { headers: { 'X-Custom-Header': 'token' } }
const specialData = await request.get('/api/special', null, config)
// const config = { headers: { 'X-Custom-Header': 'token' } }
// const specialData = await request.get('/api/special', null, config)
} catch (error) {
console.error('请求失败:', error)
} finally {
@ -36,13 +36,13 @@ const fetchData = async () => {
}
// POST
const createItem = async () => {
try {
const payload = { name: '新项目', status: 'active' }
const res = await request.post('/api/items', payload)
console.log('创建成功:', res)
} catch (error) {
console.error('创建失败:', error)
}
}
// const createItem = async () => {
// try {
// const payload = { name: '', status: 'active' }
// const res = await request.post('/api/items', payload)
// console.log(':', res)
// } catch (error) {
// console.error(':', error)
// }
// }
</script>

View File

@ -18,6 +18,7 @@ a {
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
@ -46,9 +47,11 @@ button {
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
@ -70,9 +73,11 @@ button:focus-visible {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}

View File

@ -3,17 +3,33 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"] //
"@/*": [
"src/*"
]
//
},
"jsx": "preserve",
// Vue JSX
"types": [
"vite/client",
"vue"
],
// Vue
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
// "erasableSyntaxOnly": true, //
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
// "noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue", // Vue
"vite.config.ts", // Vite
"src/main.ts" //
]
}

4
tsconfig.eslint.json Normal file
View File

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "src/**/*.vue", "vite.config.ts"] //
}

View File

@ -17,9 +17,17 @@
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"erasableSyntaxOnlsy": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
// "include": ["vite.config.ts"]
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue", // Vue
"vite.config.ts", // Vite
"src/main.ts" //
]
}