Created
December 20, 2024 10:15
-
-
Save languanghao/a983fad14e2754a82be7508afeccc6ba to your computer and use it in GitHub Desktop.
vue3+eslint8 eslint config. Support mix lang="js" and lang="ts"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { resolve } = require('node:path') | |
const fs = require('node:fs') | |
/** | |
* 不是ts写的vue文件 | |
* @type {string[]} | |
*/ | |
const vueJsFiles = [] | |
/** | |
* 用ts写的vue文件 | |
* @type {string[]} | |
*/ | |
const vueTsFiles = [] | |
// 遍历所有vue文件,将ts写的vue文件放到vueTsFiles,js写的vue文件放到vueJsFiles | |
require('fast-glob') | |
.sync(['**/*.vue', '!**/node_modules/**'], { cwd: resolve() }) | |
.forEach((filePath) => { | |
const content = fs.readFileSync(filePath, 'utf8') | |
if (/<script[^>]*\blang\s*=\s*"ts"[^>]*>/i.test(content)) | |
vueTsFiles.push(filePath) | |
else | |
vueJsFiles.push(filePath) | |
}) | |
const espree = require('eslint') | |
const tsParser = require('@typescript-eslint/parser') | |
/** | |
* vue文件的规则 | |
*/ | |
const sfcFilesRule = { | |
'vue/html-indent': [ | |
'error', | |
2, | |
{ | |
attribute: 1, | |
baseIndent: 1, | |
closeBracket: 0, | |
alignAttributesVertically: true, | |
ignores: [], | |
}, | |
], | |
'vue/script-indent': ['error', 2, { | |
baseIndent: 0, | |
switchCase: 1, | |
}], | |
'vue/max-attributes-per-line': [ | |
'error', | |
{ | |
singleline: 4, | |
multiline: 1, | |
}, | |
], | |
'vue/html-closing-bracket-newline': ['error', { | |
singleline: 'never', | |
multiline: 'always', | |
}], | |
'vue/first-attribute-linebreak': ['error', { | |
singleline: 'beside', | |
multiline: 'beside', | |
}], | |
'vue/valid-define-props': 'off', | |
'vue/v-on-event-hyphenation': ['error', 'always', { | |
autofix: false, | |
ignore: ['update:modelValue'], | |
}], | |
'vue/v-slot-style': ['error', { | |
atComponent: 'shorthand', | |
default: 'shorthand', | |
named: 'shorthand', | |
}], | |
'vue/singleline-html-element-content-newline': 'off', | |
'vue/html-closing-bracket-spacing': ['error', { | |
startTag: 'never', | |
endTag: 'never', | |
selfClosingTag: 'always', | |
}], | |
'vue/multi-word-component-names': 'off', | |
} | |
/** | |
* ts文件的规则 | |
*/ | |
const tsFileRules = { | |
'@stylistic/indent': ['error', 2], // 缩进长度 | |
'@stylistic/quotes': ['error', 'single'], // 使用单引号 | |
'@stylistic/semi': ['error', 'never'], // 不允许结尾分号 | |
'@stylistic/comma-dangle': ['error', { | |
arrays: 'always-multiline', | |
objects: 'always-multiline', | |
imports: 'always-multiline', | |
exports: 'always-multiline', | |
functions: 'ignore', | |
}], // 结尾的逗号样式 | |
'@stylistic/member-delimiter-style': ['error', { | |
multiline: { delimiter: 'none' }, | |
singleline: { delimiter: 'comma' }, | |
}], // 接口的成员不允许分号结尾 | |
'@stylistic/no-trailing-spaces': ['error', { | |
skipBlankLines: true, | |
ignoreComments: true, | |
}], // 行尾空白 | |
'@stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true }], // 大括号样式 | |
'no-tabs': ['error', { allowIndentationTabs: true }], // 不允许使用 tab | |
'object-curly-spacing': ['error', 'always'], // 确保括号内的间距一致 | |
'no-mixed-spaces-and-tabs': 'error', // 不允许混合空格和 tab | |
'space-before-function-paren': ['error', { | |
anonymous: 'always', | |
named: 'never', | |
asyncArrow: 'always', | |
}], // 函数括号前后空格 | |
'object-property-newline': ['error', { allowAllPropertiesOnSameLine: true }], // 对象属性换行 | |
'newline-per-chained-call': ['error', { ignoreChainWithDepth: 3 }], // 链式调用换行 | |
'no-unused-vars': 'off', | |
'@typescript-eslint/no-non-null-assertion': 'off', // 允许使用!! 非空判断 | |
'@typescript-eslint/explicit-module-boundary-types': 'off', // 每个方法都要明确返回值 | |
'@typescript-eslint/array-type': 'warn', // 使用 T[] 替代 Array<T> | |
'@typescript-eslint/no-require-imports': 'off', // 允许使用 require 导入 | |
// 下面这个规则有bug,使用ide的配置强制实现,分别对应在 .vscode/settings.json 和 .editorconfig | |
// '@typescript-eslint/consistent-type-imports': ['error', { | |
// prefer: 'type-imports', | |
// disallowTypeAnnotations: true, | |
// fixStyle: 'separate-type-imports', | |
// }], // 使用 import type 替代 import | |
// 允许特殊字符 | |
'no-irregular-whitespace': ['error', { | |
skipStrings: true, | |
skipComments: true, | |
skipRegExps: true, | |
skipTemplates: true, | |
}], | |
} | |
/** | |
* js文件规则 | |
*/ | |
const jsFileRules = { | |
// Common | |
'semi': ['error', 'never'], | |
'curly': ['error', 'multi-or-nest', 'consistent'], | |
'quotes': ['error', 'single'], | |
'quote-props': ['error', 'consistent-as-needed'], | |
'no-param-reassign': 'off', | |
'array-bracket-spacing': ['error', 'never'], | |
'brace-style': ['error', 'stroustrup', { allowSingleLine: true }], | |
'block-spacing': ['error', 'always'], | |
'camelcase': 'off', | |
'comma-spacing': ['error', { | |
before: false, | |
after: true, | |
}], | |
'comma-style': ['error', 'last'], | |
'comma-dangle': ['error', 'always-multiline'], | |
'no-constant-condition': 'warn', | |
// 'no-debugger': 'error', | |
// 'no-console': ['error', { allow: ['warn', 'error'] }], | |
'no-cond-assign': ['error', 'always'], | |
'func-call-spacing': ['off', 'never'], | |
'key-spacing': ['error', { | |
beforeColon: false, | |
afterColon: true, | |
}], | |
'indent': ['error', 2, { | |
SwitchCase: 1, | |
VariableDeclarator: 1, | |
outerIIFEBody: 1, | |
}], | |
'no-restricted-syntax': [ | |
'error', | |
// 'DebuggerStatement', | |
'LabeledStatement', | |
'WithStatement', | |
], | |
'object-curly-spacing': ['error', 'always'], | |
'no-return-await': 'off', | |
'space-before-function-paren': [ | |
'error', | |
{ | |
anonymous: 'always', | |
named: 'never', | |
asyncArrow: 'always', | |
}, | |
], | |
// es6 | |
'no-var': 'error', | |
'prefer-const': [ | |
'error', | |
{ | |
destructuring: 'all', | |
ignoreReadBeforeAssign: true, | |
}, | |
], | |
'prefer-arrow-callback': [ | |
'error', | |
{ | |
allowNamedFunctions: false, | |
allowUnboundThis: true, | |
}, | |
], | |
'object-shorthand': [ | |
'error', | |
'always', | |
{ | |
ignoreConstructors: false, | |
avoidQuotes: true, | |
}, | |
], | |
'prefer-exponentiation-operator': 'error', | |
'prefer-rest-params': 'error', | |
'prefer-spread': 'error', | |
'prefer-template': 'error', | |
'template-curly-spacing': 'error', | |
'arrow-parens': ['error', 'as-needed', { requireForBlockBody: true }], | |
'generator-star-spacing': 'off', | |
'spaced-comment': ['error', 'always', { | |
line: { | |
markers: ['/'], | |
exceptions: ['/', '#'], | |
}, | |
block: { | |
markers: ['!'], | |
exceptions: ['*'], | |
balanced: true, | |
}, | |
}], | |
// best-practice | |
'array-callback-return': 'error', | |
'block-scoped-var': 'error', | |
'consistent-return': 'off', | |
'complexity': ['off', 11], | |
'eqeqeq': ['error', 'smart'], | |
'no-alert': 'warn', | |
'no-case-declarations': 'error', | |
'no-multi-spaces': 'error', | |
'no-multi-str': 'error', | |
'no-with': 'error', | |
'no-void': 'error', | |
'no-useless-escape': 'off', | |
'vars-on-top': 'error', | |
'require-await': 'off', | |
'no-return-assign': 'off', | |
'operator-linebreak': ['error', 'before'], | |
'max-statements-per-line': ['error', { max: 1 }], | |
} | |
module.exports = { | |
env: { | |
node: true, | |
}, | |
globals: { | |
process: true, | |
}, | |
plugins: ['vue', '@stylistic', '@typescript-eslint'], | |
rules: { | |
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', | |
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', | |
}, | |
overrides: [ | |
{ | |
files: ['**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs', ...vueJsFiles], | |
extends: [ | |
'plugin:vue/vue3-recommended', | |
'eslint:recommended', | |
], | |
parser: 'vue-eslint-parser', | |
parserOptions: { | |
ecmaVersion: 2022, | |
ecmaFeatures: { | |
jsx: true, | |
}, | |
parser: espree, | |
}, | |
rules: { | |
...jsFileRules, | |
...sfcFilesRule, | |
'vue/no-v-html': 'off', | |
}, | |
}, | |
{ | |
files: ['**/*.ts', '**/*.tsx', '**/*.cts', '**/*.mts', ...vueTsFiles], | |
extends: [ | |
'plugin:vue/vue3-recommended', | |
'plugin:@typescript-eslint/recommended', | |
], | |
parser: 'vue-eslint-parser', | |
parserOptions: { | |
ecmaVersion: 2022, | |
ecmaFeatures: { | |
jsx: true, | |
}, | |
parser: tsParser, | |
}, | |
rules: { | |
...tsFileRules, | |
...sfcFilesRule, | |
}, | |
}, | |
], | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you migate a vue project from js to ts, eslint can't apply
vue sfc file
to different rules by<script lang="ts">
or<script lang="js">
.