eslint9

13 阅读4分钟
pnpm create @eslint/config@latest
pnpm i -D eslint-config-prettier eslint-import-resolver-node eslint-plugin-file-progress eslint-plugin-import eslint-plugin-prettier eslint-plugin-tailwindcss eslint-plugin-vue eslint-import-resolver-alias prettier
"lint": "eslint . --fix",
"format": "prettier . --write"
import js from '@eslint/js'
import configPrettier from 'eslint-config-prettier'
import progress from 'eslint-plugin-file-progress'
import importPlugin from 'eslint-plugin-import'
import pluginPrettier from 'eslint-plugin-prettier'
import tailwind from 'eslint-plugin-tailwindcss'
import pluginVue from 'eslint-plugin-vue'
import globals from 'globals'
import autoImportGlobals from './.eslintrc-auto-import.json' with { type: 'json' }

export default [
	// 文件进度插件配置(显示 lint 进度)
	progress.configs.recommended,
	// 全局忽略文件(优化:使用更精确的匹配模式)
	{
		ignores: [
			'node_modules/**',
			'dist/**',
			'build/**',
			'vite/**',
			'scripts/**',
			'public/**',
			'coverage/**',
			'**/auto-imports.d.ts',
			'**/components.d.ts',
			'**/typings/*.d.ts',
			'.vscode/**',
			'.idea/**',
			'vite.config.mjs',
			'**/*.min.js',
			'**/*.min.css',
			'**/*.mjs',
			'**/*.log',
			'**/Xn*/**',
			'**/tinymce/**',
			'.eslintrc-auto-import.json',
			'src/components/**',
		],
	},
	// JavaScript 推荐配置
	js.configs.recommended,
	// 通用配置(适用于所有 JS/Vue 文件)
	{
		files: ['**/*.{js,mjs,cjs,vue}'],
		plugins: {
			prettier: pluginPrettier,
			import: importPlugin,
		},
		languageOptions: {
			globals: {
				...globals.browser,
				...globals.node,
				...autoImportGlobals.globals,
				hiprint: 'readonly',
				$: 'readonly',
				AMap: 'readonly',
				AMapUI: 'readonly',
				BMapGL: 'readonly',
				tinymce: 'readonly',
				arguments: 'readonly',
				ZwLog: 'readonly',
				T: 'readonly',
			},
			ecmaVersion: 'latest',
			sourceType: 'module',
		},
		settings: {
			'import/resolver': {
				node: {
					extensions: ['.js', '.jsx', '.mjs', '.cjs', '.vue'],
					moduleDirectory: ['node_modules', 'src'],
					resolvePaths: ['.'],
					tryExtensions: ['.js', '.jsx', '.mjs', '.cjs', '.vue', '.json'],
				},
			},
			'import/core-modules': [],
			'import/ignore': ['node_modules', '\\.(coffee|scss|css|less|hbs|svg|json)$'],
			'import/external-module-folders': ['node_modules'],
		},
		rules: {
			'prettier/prettier': 'error',
			'no-unused-vars': [
				'error',
				{
					argsIgnorePattern: '^_',
					ignoreRestSiblings: true,
					varsIgnorePattern: '^_',
					caughtErrors: 'all',
					destructuredArrayIgnorePattern: '^_',
				},
			],
			// 代码质量规则
			'no-console': ['warn', { allow: ['warn', 'error'] }],
			'no-debugger': 'warn',
			'no-alert': 'warn',
			'no-var': 'error',
			'prefer-const': 'error',
			'no-eval': 'warn',
			'no-new-func': 'warn',
			'no-return-await': 'warn',
			'require-await': 'warn',
			'prefer-arrow-callback': 'warn',
			// 避免常见错误
			'no-unreachable': 'error',
			'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
			// 方法/函数之间自动加空行(仅对 function 声明生效;const fn = () => {} 无法用内置规则区分变量)
			'padding-line-between-statements': ['error', { blankLine: 'always', prev: 'function', next: 'function' }],
			// 关闭 ESLint 内置的 no-duplicate-imports,使用 import/no-duplicates(支持自动修复)
			'no-duplicate-imports': 'off',
			'array-callback-return': 'error',
			'object-shorthand': ['warn', 'always'],
			curly: ['error', 'all'],
			eqeqeq: ['error', 'smart'],
			'no-implied-eval': 'error',
			// 自动合并重复导入(支持自动修复)
			'import/no-duplicates': ['error', { 'prefer-inline': false }],
			// 自动排序导入语句(支持自动修复)
			'import/order': [
				'error',
				{
					groups: [
						'builtin', // Node.js 内置模块(如 fs, path)
						'external', // 外部依赖(如 vue, axios)
						'internal', // 内部模块(通过路径别名,如 @/)
						'parent', // 父级目录导入(../)
						'sibling', // 同级目录导入(./)
						'index', // 索引文件导入(./index)
					],
					'newlines-between': 'never', // 组之间不添加空行
					alphabetize: {
						order: 'asc', // 按字母顺序排序
						caseInsensitive: true, // 不区分大小写
					},
					warnOnUnassignedImports: true, // 对未使用的导入发出警告
				},
			],
			// 优化:添加更多 import 相关规则
			// 未解析导入检查。node 解析器无法解析 @/、~/ 别名,故忽略以免误报;若接入 eslint-import-resolver-alias 可去掉 ignore
			'import/no-unresolved': [
				'error',
				{
					caseSensitive: true,
					commonjs: true,
					ignore: ['^@/', '^~/'],
				},
			],
			'import/no-cycle': ['warn', { maxDepth: 3 }], // 检测循环依赖
			'import/no-self-import': 'error', // 禁止自己导入自己
			'import/no-absolute-path': 'error', // 禁止使用绝对路径导入
			'import/no-useless-path-segments': [
				'error',
				{
					noUselessIndex: true, // 禁止使用 /index
					commonjs: true,
				},
			], // 禁止无用的路径段
			'import/no-unused-modules': 'off', // 关闭,性能影响较大
			'import/no-deprecated': 'warn', // 警告使用已废弃的模块
			'import/no-extraneous-dependencies': [
				'error',
				{
					devDependencies: [
						'**/*.test.{js,jsx,ts,tsx}',
						'**/*.spec.{js,jsx,ts,tsx}',
						'**/vite.config.*',
						'**/vitest.config.*',
						'**/eslint.config.*',
						'**/prettier.config.*',
						'**/tailwind.config.*',
						'**/postcss.config.*',
					],
					optionalDependencies: false,
					peerDependencies: false,
				},
			], // 禁止引入未在 package.json 中声明的依赖
			'import/no-mutable-exports': 'error', // 禁止导出可变绑定
			'import/no-named-as-default': 'warn', // 警告使用与默认导出同名的命名导出
			'import/no-named-as-default-member': 'warn', // 警告使用与默认导出同名的命名导出成员
			'import/no-named-default': 'error', // 禁止使用命名默认导出
			'import/no-default-export': 'off', // 关闭,允许默认导出
			'import/prefer-default-export': 'off', // 关闭,不强制默认导出
			'import/exports-last': 'off', // 关闭,不强制导出在最后
			'import/group-exports': 'off', // 关闭,不强制分组导出
			'import/dynamic-import-chunkname': 'off', // 关闭,动态导入 chunk 名称
			'import/no-import-module-exports': 'error', // 禁止在模块导出中使用 import
			'import/no-relative-packages': 'warn', // 警告使用相对路径导入包
			'import/no-relative-parent-imports': 'off', // 关闭,允许相对父级导入
			'import/no-restricted-paths': 'off', // 关闭,不限制特定路径
			'import/no-internal-modules': 'off', // 关闭,允许内部模块导入
			'import/no-unassigned-import': 'off', // 关闭,允许未赋值导入(用于副作用)
			'import/no-amd': 'error', // 禁止 AMD 格式
			'import/no-commonjs': 'off', // 关闭,允许 CommonJS
			'import/no-nodejs-modules': 'off', // 关闭,允许 Node.js 模块
			'import/first': 'error', // 导入必须在文件顶部
			'import/newline-after-import': ['error', { count: 1 }], // 导入后必须有空行
			'import/no-namespace': 'off', // 关闭,允许命名空间导入
		},
	},
	// Vue 配置
	...pluginVue.configs['flat/strongly-recommended'],
	{
		files: ['**/*.vue'],

		rules: {
			'vue/multi-word-component-names': 'off',
			'vue/require-prop-types': 'off',
			'vue/block-order': [
				'error',
				{
					order: ['template', 'script', 'style'],
				},
			],
			// Vue 最佳实践
			'vue/component-name-in-template-casing': ['error', 'PascalCase'],
			'vue/no-v-html': 'warn',
			'vue/require-default-prop': 'off',
			'vue/require-explicit-emits': 'error',
			'vue/no-multiple-slot-args': 'error',
			// 组合式 / <script setup> 宏顺序规范
			'vue/define-macros-order': [
				'warn',
				{
					order: ['defineOptions', 'defineModel', 'defineProps', 'defineEmits', 'defineSlots'],
				},
			],
			'vue/prefer-define-options': 'warn', // 推荐使用 defineOptions
			// 模板属性顺序:指令 / 绑定 / 事件 有固定排序,减小 diff 噪音
			'vue/attributes-order': [
				'error',
				{
					order: [
						'DEFINITION', // is, v-is
						'LIST_RENDERING', // v-for
						'CONDITIONALS', // v-if / v-else-if / v-else / v-show / v-cloak
						'RENDER_MODIFIERS', // v-once / v-pre
						'GLOBAL', // id
						'UNIQUE', // key / ref / slot / slot-scope / is
						'TWO_WAY_BINDING', // v-model
						'OTHER_DIRECTIVES', // 其它指令
						'OTHER_ATTR', // 其它属性
						'EVENTS', // v-on
						'CONTENT', // v-html / v-text
					],
					alphabetical: false,
				},
			],
		},
	},
	// Tailwind CSS 配置
	...tailwind.configs['flat/recommended'],
	{
		files: ['**/*.{vue,js,jsx}'],
		rules: {
			'tailwindcss/no-custom-classname': 'off',
			// 优化:可以添加更多 Tailwind 相关规则
			'tailwindcss/classnames-order': 'warn', // 警告类名顺序问题
		},
	},

	// Prettier 配置(必须放在最后,用于覆盖冲突的规则)
	configPrettier,
]