Skip to content
On this page

vue3 + Vite 配置 Eslint + Prettier + husky + vsCode

为了保证高质量的代码,尽量减少和提早发现一些错误。使用eslint可以在工程中保证一致的代码风格,特别是当工程变得越来越大、越来越多的人参与进来时,需要加强一些最佳实践。

本文主要介绍在dt-frames中如何配置eslint,其他框架类似。

安装eslint依赖包

js
pnpm add -D eslint eslint-plugin-import eslint-plugin-vue eslint-plugin-prettier eslint-config-prettier @babel/eslint-parser

初始化eslint

js
// 初始化 如果没有npx 运行 yarn install -g npx
npx eslint --init

// 选择模式: How would you like to use ESLint?
> To check syntax and find problems

// 选择语言模块: What type of modules does your project use?
> JavaScript modules (import/export)

// 选择语言框架: Which framework does your project use?
> Vue.js

// 是否使用ts: Does your project use TypeScript?
> Yes

// 代码在哪里运行(用空格选中 Browser + Node): Where does your code run
√ Browser
√ Node

// 您希望您的配置文件是什么格式: What format do you want your config file to be in? ...

> JavaScript

安装完成后,会在根目录生成.eslintrc.cjs,并且将内容修改如下:

js
module.exports = {
	env: {
		browser: true,
		es2021: true,
		jest: true
	},

	// 规则继承
	extends: [
		// 函数不能重名,对面不能重复key等
		'eslint:recommended',
		// ts语法规则
		'plugin:@typescript-eslint/recommended',
		// vue3语法规则
		'plugin:vue/vue3-essential',
		'plugin:prettier/recommended'
	],

	// 为特定类型的文件指定处理器
	overrides: [
		{
			env: {
				node: true
			},
			files: ['.eslintrc.{js,cjs}'],
			parserOptions: {
				sourceType: 'script'
			}
		}
	],

	// 指定解析器
	parserOptions: {
		// 检测ECMA最新版本
		ecmaVersion: 'latest',
		// ts解析器
		parser: '@typescript-eslint/parser',
		sourceType: 'module',
		jsxPragma: 'React',
		ecmaFeatures: {
			jsx: true
		}
	},
	plugins: [
		// eslint-plugin-前缀可以从插件名称省略
		// 检测ts语法插件
		'@typescript-eslint',
		// 检测vue语法插件
		'vue'
	],
	rules: {
		// eslint (https://eslint.bootscss.com/docs/rules/)
		'no-var': 'error',
		'no-multiple-empty-lines': ['warn', { max: 2 }],
		'no-useless-escape': 'off',

		// typescript (https://typescript-eslint.io/rules)
		'@typescript-eslint/no-unused-vars': 'error',
		'@typescript-eslint/prefer-ts-expect-error': 'error',
		'@typescript-eslint/no-explicit-any': 'off',
		'@typescript-eslint/no-non-null-assertion': 'off',
		'@typescript-eslint/semi': 'off',
		'@typescript-eslint/no-namespace': 'off',

		// eslint-plugin-vue (https://eslint.vuejs.org/rules/)
		'vue/multi-word-component-names': 'off',
		'vue/script-setup-uses-vars': 'error',
		// 不允许修改props属性
		'vue/no-mutating-props': 'off',
		'vue/attribute-hyphenation': 'off',

		'prettier/prettier': [
			'error',
			{
				semi: false,
				trailingComma: 'none',
				singleQuote: true,
				useTabs: true,
				endOfLine: 'auto'
			}
		]
	}
}

并不是所有的文件都需要进行eslint检测,添加检测忽略文件.eslintignore

js
# 忽略目录
/dist
/build
/public
/node_modules

/packages

# 忽略文件
**/*-min.js
**/*.min.js
**/*-min.css
**/*.min.css
pnpm-lock.yaml
yarn-lock.yaml

在packages中新增两个运行脚本:

js
"scripts": {
	"lint": "eslint ./src/**/*.{js,ts,tsx,vue,jsx}",
	"lint:fix": "eslint ./src/**/*.{js,ts,tsx,vue,jsx} --fix"
}

配置 .prettierrc

安装依赖:

js
pnpm install -D eslint-plugin-prettier prettier eslint-config-prettier

根目录下新建.prettierrc.json,同时配置以下参数:

js
{
	// 代码结尾是否加分号
	semi: false,

	// 使用4个空格缩进
	tabWidth: 4,

	// 代码末尾不需要逗号
	trailingComma: 'none',

	// 文件换行格式
	endOfLine: 'auto',

	// 超过多少字符强制换行
	printWidth: 120,

	// 是否使用单引号
	singleQuote: true,
	vueIndentScriptAndStyle: true,

	// 单个参数的箭头函数不加括号 x => x
	arrowParens: 'avoid',

	// 对象大括号内两边是否加空格
	bracketSpacing: true,

	// 不使用缩进符,而使用空格
	useTabs: true,

	// 对象的key仅在必要时用引号
	quoteProps: 'as-needed',

	// jsx不使用单引号,而使用双引号
	jsxSingleQuote: false,

	// jsx标签的反尖括号需要换行
	jsxBracketSameLine: false,

	// 每个文件格式化的范围是文件的全部内容
	rangeStart: 0,

	// 结尾
	rangeEnd: Infinity,

	// 不需要写文件开头的 @prettier
	requirePragma: false,

	// 不需要自动在文件开头插入 @prettier
	insertPragma: false,

	// 使用默认的折行标准
	proseWrap: 'preserve',

	// 解决尖括号自动占一行
	htmlWhitespaceSensitivity: 'ignore',

    // 不让prettier使用eslint的代码格式进行校验
    eslintIntegration: false,

    // 不使用prettier格式化的文件填写在项目的.prettierignore文件中
    ignorePath: '.prettierignore'
}

配置不需要代码格式化的文件, 在根目录下创建.prettierignore(注意:文件没有后缀),忽略的内容如下:

# Logs
logs
*.log
pnpm-error.*

public
node_modules
dist
dist-ssr
*.local
**/*.svg
**/*.sh

# Editor directories and files
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

配置格式化脚本

js
{
	"scripts": {
		"format": "prettier --write \"./**/*.{html,vue,tsx,ts,js,json,md}\"",
	}
}

配置Eslint

如果使用了自动导入插件unplugin-auto-import/vite,则需要配置插件:

js
...
AutoImport({
    eslintrc: {
        enabled: true
    },
    imports: ['vue', 'vue-router'],
    dts: 'src/auto-import.d.ts'
})
...

.eslintrc.js中配置一下信息:

js
module.exports = {
	extends: [
		'./.eslintrc-auto-import.json',         // 如果使用了unplugin-auto-import/vite
		...
	]
}

配置stylelint

官网: https://stylelint.bootcss.com/

js
pnpm add -D stylelint-config-standard stylelint-config-html stylelint-config-standard-scss stylelint-config-recommended-vue stylelint-config-recess-order stylelint-config-prettier

配置.stylelintrc.cjs

js
module.exports = {
	extends: [
		'stylelint-config-standard',
		// 配置vue中template样式格式化
		'stylelint-config-html/vue',
		// stylelint scss插件
		'stylelint-config-standard-scss',
		// 配置vue中的scss样式格式化
		'stylelint-config-recommended-vue/scss',
		// css书写顺序
		'stylelint-config-recess-order',
		// 配置style与prettier的兼容
		'stylelint-config-prettier'
	],
	overrides: [
		{
			files: ['**/*.(scss|css|vue|html)'],
			customSyntax: 'postcss-scss'
		},
		{
			files: ['**/*.(html|vue)'],
			customSyntax: 'postcss-html'
		}
	],
	ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts', '**/*.json', '**/*.md', '**/*.yaml'],
	rules: {
		// 在css中使用v-bind不报错
		'value-keyword-case': null,
		// 禁止在较高优先级的选择器后面出现被其覆盖的较低优先级的选择器
		'no-descending-specificity': null,
		// url的引号必须有
		'function-url-quotes': 'always',
		// 关闭禁止空源码
		'no-empty-source': null,
		// 关闭强制选择器类名的格式
		'selector-class-pattern': null,
		// 禁止未知的属性
		'property-no-unknown': true,
		// 关闭属性前缀 --webkit-box
		'value-no-vendor-prefix': null,
		'property-no-vendor-prefix': null,
        // 使用单引号
        'string-quotes': 'single',
        // 深度嵌套
        'max-nesting-depth': 5,
		'selector-pseudo-class-no-unknown': [
			true,
			{
				ignorePseudoClasses: ['global', ':deep'] // 忽略属性
			}
		]
	}
}

配置.stylelintignore

js
/node_modules/*
/dist/*
/public/*

配置修复命令

js
{
	"scripts": {
		"lint:style": "stylelint ./src/**/*.{css,scss,vue} --cache --fix",
	}
}

配置husky

我们做了很多的代码检查,代码格式化,但是有一个问题,就是需要手动去执行命令才能生效,如果我们不手动执行命令,直接把代码推到git上,那么我们上面配置的所有内容均是没有意义的。为了保证代码上传到git之前,我们需要做一个git的hook拦截,将代码格式化以后再推到git上。

安装husky

js
pnpm add -D husky
npx husky-init

在跟目录下会生成.husky文件夹,配置pre-commit内容如下:

js
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# 代码提交到远程仓库之前会执行的命令
pnpm run format
pnpm run lint:fix

配置commitlint

对于我们的commit信息,也是有统一规范的,不能随便写,应该按照统一的标准来执行,我们可以利用commitlint来显现。

js
pnpm add -D @commitlint/config-conventional @commitlint/cli

在根目录下新建 commitlint.config.cjs(注意是cjs),并配置一下信息:

js
module.exports = {
	extends: ['@commitlint/config-conventional'],
	// 校验规则
	rules: {
		'type-enum': [
			2,
			'always',
			[
				'feat', // 新特性、新功能
				'fix', // 修改bug
				'docs', // 文档修改
				'style', // 代码格式修改,注意 不是css修改
				'refactor', // 代码重构
				'perf', // 优化相关,比如提升性能、体验等
				'test', // 测试用例修改
				'chore', // 其他修改,比如改变构建流程、或者增加依赖库、工具等
				'revert', // 回滚到上一版本
				'build' // 编译相关的修改,例如发布版本、对项目构建相关的改变
			]
		],
		'type-case': [0],
		'type-empty': [0],
		'scope-empty': [0],
		'scope-case': [0],
		'subject-full-stop': [0, 'never'],
		'subject-case': [0, 'never'],
		'header-max-length': [0, 'always', 72]
	}
}

在package.json中配置以下信息:

js
{
	"script": {
		"commitlint": "commitlint --config commitlint.config.cjs -e -V"
	}
}

配置husky

js
npx husky add .husky/commit-msg

// 在.husky/commit-msg中配置 ===start==
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

pnpm run commitlint
//===end==

此时git提交代码的备注信息必须带有关键字,如 'feat: 修改格式'(注意:关键字后面要有英文冒号+空格+备注信息)

pnpm包管理工具

团队开发项目的时候,需要统一包管理工具,因为不同包管理工具下载同一个依赖,可能版本不一样,导致出现bug。

在根目录创建script/preinstall.js文件,添加以下内容:

js
if (!/pnpm/.test(process.env.npm_execpath || '')) {
	console.warn(
		`\u001b[33mThis repository must using pnpm as the package manager` +
			` for scripts to work properly . \u001b[39m\n`
	)

	process.exit(1)
}

配置vscode

在根文件夹中新建.vscode文件夹, 然后创建 extensions.jsonsettings.json

extensions.json中配置常用的vscode插件,内容如下:

json
{
    "recommendations": [
        "ant-design-vue.vscode-ant-design-vue-helper",
        "Vue.volar",
        "bradlc.vscode-tailwindcss",
        "esbenp.prettier-vscode",
        "ms-vscode.vscode-typescript-next",
        "rvest.vs-code-prettier-eslint",
        "dbaeumer.vscode-eslint"
    ]
}

settings.json 中配置编辑器信息:

json
{
    "files.associations": {
        "*.json": "jsonc"
    },
    "prettier.singleQuote": true,
    "editor.codeActionsOnSave": {
        "source.fixAll": true,
        "source.fixAll.eslint": true,
        "source.fixAll.stylelint": true
    }
}

更多内容,请参考 vscode之setting

TIP

如果不生效,重启vscode,或者改变文件名称试试,如把.prettierrc.js改为.prettierrc, 再改成.prettierrc.js