一、安装esilnt
npm install -D eslint
二、配置eslint
npx eslint --init
(1)第一步:选择第三个:检查语法、发现问题、并且强制使用
(2)选择JavaScript
(3)选择vue
(4)项目是否使用ts;选择Yes
(5)你的代码运行的环境:选择浏览器和node环境
(6)选择使用github上的一些流行的风格
(7)这里选择第一个
(8)想要最后的配置是以什么格式;选择js
(9)会检查你缺少的依赖:是否想要安装他们:这里选择是
(10)使用什么安装
最终:
注意:以上步骤执行完毕会自动在项目根目录下生成 .eslintrc.js 内容如下
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'plugin:vue/vue3-essential',
'standard-with-typescript'
],
overrides: [
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: [
'vue'
],
rules: {
}
}
测试:在项目package.json中加上以下脚本;并在项目中运行npm run lint
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .eslintignore",
三、eslint中添加解析器
添加解析器:ts的解析器@typescript-eslint/parser以及vue的解析器 vue-eslint-parser
安装:
npm install -D @typescript-eslint/parser vue-eslint-parser
修改.eslintrc.js文件:
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: ['plugin:vue/vue3-essential', 'standard-with-typescript', 'plugin:prettier/recommended'],
overrides: [],
parser: 'vue-eslint-parser',//vue解析器
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: [
'./tsconfig.json',
'./tsconfig.app.json',
'./tsconfig.config.json',
'./tsconfig.vitest.json'
],
parser: '@typescript-eslint/parser'//ts解析
},
plugins: ['vue'],
rules: {}
}
四、错误处理
错误1:
Error: Error while loading rule '@typescript-eslint/dot-notation': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
解决方法: 修改.eslintrc.js,在parserOptions中新加project属性;eslint官网给的解决方法都是project: ['./tsconfig.json'];这样做完之后当前错误已修复,但是会报另外一个错误(看错误2)
错误2:
error Parsing error: ESLint was configured to run on <tsconfigRootDir>/vite.config.ts
using parserOptions.project
: /users/dengjie/workplace/项目/项目模板/leinao-vue3-template/tsconfig.json
However, that TSConfig does not include this file. Either:
- Change ESLint's list of included files to not include this file
- Change that TSConfig to include this file
- Create a new TSConfig that includes this file and include it in your parserOptions.project
See the typescript-eslint docs for more info: typescript-eslint.io/linting/tro…
以上错误是说我们在tsconfig.json没有包含这个vite.config.ts(此处只是把其中一个错误拿出来了,项目报了错误都是说找不到文件,如下截图)
此时我们看下我们的项目结构,根目录下包含了四个ts的文件,分别是:'tsconfig.json', 'tsconfig.app.json', 'tsconfig.config.json', 'tsconfig.vitest.json';这四个文件是通过tsconfig.json中使用references联系起来的;如下截图所示
我们打开以上三个文件后发现,其中include已经包含了错误2说的文件;但是为什么还是会报找不到这些文件??翻看官网文档在一个不起眼的角落看到:.eslintrc.js 中配置的project中的文件想要生效必须含有include这个属性;此处我们修改在parserOptions中的project属性;project: ['./tsconfig.json', './tsconfig.app.json', './tsconfig.config.json', './tsconfig.vitest.json'];包含所有的文件;此时再执行npm run lint发现错误2也取消了;
注意注意:如果项目框架搭建的方式不一样,可能最终的框架根目录下的ts文件名称也会不一样(我是通过npm init vue@latest这个命令搭建的),但是处理方式都是大差不差的,按照上面的配置在project中配置根目录下的参数;如果还是报错,则特别注意:ts文件中的一个baseUrl的属性,可以尝试在"baseUrl": "."和"baseUrl": "./"两者之间切换试试,看看能不能解决;
注意:有时候报错的文件的确在这些文件中没有,比如我们刚新增的.eslintrc.js;处理方法就是在ts这些配置文件中添加这个文件或者使用.eslintignore忽略这个文件
五、安装prettier
npm i prettier -D
六、配置prettier
在项目根目录下新建.prettierrc.js文件,写入以下内容(可以在官网看更多的配置 官网:prettier.io/)
{
module.exports = {
// 一行的字符数,如果超过会进行换行,默认为80
printWidth: 80,
// 一个tab代表几个空格数,默认为80
tabWidth: 2,
// 是否使用tab进行缩进,默认为false,表示用空格进行缩减
useTabs: false,
// 字符串是否使用单引号,默认为false,使用双引号
singleQuote: true,
// 行位是否使用分号,默认为true
semi: false,
// 是否使用尾逗号,有三个可选值"<none|es5|all>"
trailingComma: "none",
// 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
bracketSpacing: true
}
}
七、解决 Prettier 和 ESLint 的冲突
解决两者冲突问题,需要用到 eslint-plugin-prettier 和 eslint-config-prettier。
eslint-plugin-prettier
将 Prettier 的规则设置到 ESLint 的规则中。eslint-config-prettier
关闭 ESLint 中与 Prettier 中会发生冲突的规则。
最后形成优先级:Prettier 配置规则
> ESLint 配置规则
。
-
安装插件
npm i eslint-plugin-prettier eslint-config-prettier -D
-
在
.eslintrc.js
中的extends的最后面最后面最后面最后面最后面 添加 prettier 插件 'plugin:prettier/recommended'module.exports = { ... extends: [ 'plugin:vue/vue3-essential', 'standard-with-typescript', 'plugin:prettier/recommended' // 添加 prettier 插件 ], ... }
这样,我们在执行 eslint --fix
命令时,ESLint 就会按照 Prettier 的配置规则来格式化代码,轻松解决二者冲突问题。
集成 husky 和 lint-staged
我们在项目中已集成 ESLint 和 Prettier,在编码时,这些工具可以对我们写的代码进行实时校验,在一定程度上能有效规范我们写的代码,但团队可能会有些人觉得这些条条框框的限制很麻烦,选择视“提示”而不见,依旧按自己的一套风格来写代码,或者干脆禁用掉这些工具,开发完成就直接把代码提交到了仓库,日积月累,ESLint 也就形同虚设。
所以,我们还需要做一些限制,让没通过 ESLint 检测和修复的代码禁止提交,从而保证仓库代码都是符合规范的。
为了解决这个问题,我们需要用到 Git Hook,在本地执行 git commit
的时候,就对所提交的代码进行 ESLint 检测和修复(即执行 eslint --fix
),如果这些代码没通过 ESLint 规则校验,则禁止提交。
实现这一功能,我们借助 husky + lint-staged 。
husky —— Git Hook 工具,可以设置在 git 各个阶段(
pre-commit
、commit-msg
、pre-push
等)触发我们的命令。
lint-staged —— 在 git 暂存的文件上运行 linters。
配置 husky
-
自动配置(推荐)
使用
husky-init
命令快速在项目初始化一个 husky 配置。npx husky-init && npm install
这行命令做了四件事:
- 安装 husky 到开发依赖
2.在项目根目录下创建 `.husky` 目录
3.在 `.husky` 目录创建 `pre-commit` hook,并初始化 `pre-commit` 命令为 `npm test`
4.修改 `package.json` 的 `scripts`,增加 `"prepare": "husky install"`
到这里,husky 配置完毕,现在我们来使用它:
husky 包含很多 hook
(钩子),常用有:pre-commit
、commit-msg
、pre-push
。这里,我们使用 pre-commit
来触发 ESLint 命令。
修改 .husky/pre-commit
hook 文件的触发命令:
eslint --fix ./src --ext .vue,.js,.ts
上面这个 pre-commit
hook 文件的作用是:当我们执行 git commit -m "xxx"
时,会先对 src
目录下所有的 .vue
、.js
、.ts
文件执行 eslint --fix
命令,如果 ESLint 通过,成功 commit
,否则终止 commit
。
但是又存在一个问题:有时候我们明明只改动了一两个文件,却要对所有的文件执行 eslint --fix
。假如这是一个历史项目,我们在中途配置了 ESLint 规则,那么在提交代码时,也会对其他未修改的“历史”文件都进行检查,可能会造成大量文件出现 ESLint 错误,显然不是我们想要的结果。
我们要做到只用 ESLint 修复自己此次写的代码,而不去影响其他的代码。所以我们还需借助一个神奇的工具 lint-staged 。
配置 lint-staged
lint-staged 这个工具一般结合 husky 来使用,它可以让 husky 的 hook
触发的命令只作用于 git add
那些文件(即 git 暂存区的文件),而不会影响到其他文件。
接下来,我们使用 lint-staged 继续优化项目。
-
安装 lint-staged
npm i lint-staged -D
-
在
package.json
里增加 lint-staged 配置项![image](p3-juejin.byteimg.com/tos-cn-i-k3…
"lint-staged": { "*.{vue,js,ts}": "eslint --fix" },
这行命令表示:只对 git 暂存区的 `.vue`、`.js`、`.ts` 文件执行 `eslint --fix`。
- 修改
.husky/pre-commit
hook 的触发命令为:npx lint-staged
至此,husky 和 lint-staged 组合配置完成。
如果 ESLint 通过,成功提交,否则终止提交。从而保证了我们提交到 Git 仓库的代码都是规范的。
测试:
提交前: 新建test.ts 内容如下:age未定义
提交后:
最终文件:
.eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: ['plugin:vue/vue3-essential', 'standard-with-typescript', 'plugin:prettier/recommended'],
overrides: [],
parser: 'vue-eslint-parser',//vue解析器
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: [
'./tsconfig.json',
'./tsconfig.app.json',
'./tsconfig.config.json',
'./tsconfig.vitest.json'
],
parser: '@typescript-eslint/parser',//ts解析
extraFileExtensions: ['.vue']
},
plugins: ['vue'],
rules: {}
}
.prettierrc.js
{
module.exports = {
// 一行的字符数,如果超过会进行换行,默认为80
printWidth: 80,
// 一个tab代表几个空格数,默认为80
tabWidth: 2,
// 是否使用tab进行缩进,默认为false,表示用空格进行缩减
useTabs: false,
// 字符串是否使用单引号,默认为false,使用双引号
singleQuote: true,
// 行位是否使用分号,默认为true
semi: false,
// 是否使用尾逗号,有三个可选值"<none|es5|all>"
trailingComma: "none",
// 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
bracketSpacing: true
}
}
package.json(如果按照步骤执行后还有不能解决的错误,可以通过这个文件看下对应版本)
{
"name": "vue-project",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "run-p type-check build-only",
"preview": "vite preview",
"test:unit": "vitest --environment jsdom --root src/",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .eslintignore",
"prepare": "husky install"
},
"lint-staged": {
"*.{vue,js,ts}": "eslint --fix"
},
"dependencies": {
"less": "^4.1.3",
"vue": "^3.2.45",
"vue-router": "^4.1.6"
},
"devDependencies": {
"@types/jsdom": "^20.0.1",
"@types/node": "^18.11.12",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/test-utils": "^2.2.6",
"@vue/tsconfig": "^0.1.3",
"eslint": "^8.35.0",
"eslint-config-prettier": "^8.6.0",
"eslint-config-standard-with-typescript": "^34.0.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.6.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.9.0",
"husky": "^8.0.0",
"jsdom": "^20.0.3",
"lint-staged": "^13.1.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.8.4",
"typescript": "^4.9.5",
"vite": "^4.0.0",
"vitest": "^0.25.6",
"vue-eslint-parser": "^9.1.0",
"vue-tsc": "^1.0.12"
}
}
配置 Stylelint
stylelint为css的lint工具。可格式化css代码,检查css语法错误与不合理的写法,指定css书写顺序等...
安装(针对less)
注意:安装stylelint的时候不指定版本号各个依赖之间很大可能会出现版本冲突,导致安装失败;建议在package.json中先把以下代码复制,在进行安装
"devDependencies": {
"postcss": "^8.4.12",
"postcss-less": "^6.0.0",
"postcss-html": "^1.3.0",
"stylelint": "^14.6.0",
"stylelint-config-html": "^1.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended": "^7.0.0",
"stylelint-config-recommended-less": "^1.0.4",
"stylelint-config-recommended-scss": "^7.0.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^25.0.0",
"stylelint-config-standard-scss": "^4.0.0",
"stylelint-config-standard-vue": "^1.0.0",
"stylelint-less": "^1.0.5",
"stylelint-order": "^5.0.0",
}
npm install stylelint postcss postcss-less postcss-html stylelint-config-prettier stylelint-config-recommended-less stylelint-config-standard stylelint-config-standard-vue stylelint-less stylelint-order -D --legacy-peer-deps
- stylelint:
css
样式工具 - postcss: 转换
css
代码工具 - postcss-less: 识别
less
语法 - postcss-html: 识别html/vue 中的
<style></style>
标签中的样式 - stylelint-config-standard:
Stylelint
的标准可共享配置规则,详细可查看官方文档 - stylelint-config-prettier: 关闭所有不必要或可能与
Prettier
冲突的规则 - stylelint-config-recommended-less:
less
的推荐可共享配置规则,详细可查看官方文档 - stylelint-config-standard-vue: lint
.vue
文件的样式配置 - stylelint-less:
stylelint-config-recommended-less
的依赖,less
的stylelint
规则集合 - stylelint-order: 指定样式书写的顺序,在
.stylelintrc.js
中order/properties-order
指定顺序
增加.stylelintrc.js
配置文件
module.exports = {
extends: [
'stylelint-config-standard',
'stylelint-config-prettier',
'stylelint-config-recommended-less',
'stylelint-config-standard-vue'
],
plugins: ['stylelint-order'],
// 不同格式的文件指定自定义语法
overrides: [
{
files: ['**/*.(less|css|vue|html)'],
customSyntax: 'postcss-less'
},
{
files: ['**/*.(html|vue)'],
customSyntax: 'postcss-html'
}
],
ignoreFiles: [
'**/*.js',
'**/*.jsx',
'**/*.tsx',
'**/*.ts',
'**/*.json',
'**/*.md',
'**/*.yaml'
],
rules: {
'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
'selector-pseudo-element-no-unknown': [
true,
{
ignorePseudoElements: ['v-deep']
}
],
'selector-pseudo-class-no-unknown': [
true,
{
ignorePseudoClasses: ['deep']
}
],
// 指定样式的排序
'order/properties-order': [
'position',
'top',
'right',
'bottom',
'left',
'z-index',
'display',
'justify-content',
'align-items',
'float',
'clear',
'overflow',
'overflow-x',
'overflow-y',
'padding',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'margin',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'width',
'min-width',
'max-width',
'height',
'min-height',
'max-height',
'font-size',
'font-family',
'text-align',
'text-justify',
'text-indent',
'text-overflow',
'text-decoration',
'white-space',
'color',
'background',
'background-position',
'background-repeat',
'background-size',
'background-color',
'background-clip',
'border',
'border-style',
'border-width',
'border-color',
'border-top-style',
'border-top-width',
'border-top-color',
'border-right-style',
'border-right-width',
'border-right-color',
'border-bottom-style',
'border-bottom-width',
'border-bottom-color',
'border-left-style',
'border-left-width',
'border-left-color',
'border-radius',
'opacity',
'filter',
'list-style',
'outline',
'visibility',
'box-shadow',
'text-shadow',
'resize',
'transition'
]
}
}
新增校验脚本:package.json 脚本
"lint:style": "stylelint \"./**/*.{css,less,vue,html}\" --fix",
执行 npm run lint:style 即可针对项目的样式进行校验和修复
在vscode中使用stylelint
(1)打开VScode的设置,修改settings.json,保存文件时自动保存
//开启自动修复
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": true, // 开启stylelint自动修复
},
// 配置stylelint检查的文件类型范围
"stylelint.validate": [
"css",
"less",
"postcss",
"scss",
"sass",
"vue"
],
"stylelint.enable": true,
"css.validate": false,
"less.validate": false,
"scss.validate": false,
代码提交规范
前面我们已经统一代码规范,并且在提交代码时进行强约束来保证仓库代码质量。多人协作的项目中,在提交代码这个环节,也存在一种情况:不能保证每个人对提交信息的准确描述,因此会出现提交信息紊乱、风格不一致的情况。
以下我们使用社区的 Angular 团队提交规范。 先看看Angular的提交记录
commit message 提交
commit message 由 Header、Body、Footer 组成。
Header
Header 部分包括三个字段 type(必需)、scope(可选)和 subject(必需)。
<type>(<scope>): <subject>
- type(必须):用于规范提交的类型,必须是以下几种类型
- scope(可选):表示影响的范围,比如组件,依赖库等
- subject(必须): 对本次提交简短的描述
body(可省略)
对本次提交代码的详细描述
footer(可省略)
如果本次提交的代码是突破性的变更或关闭缺陷,则 Footer 必需,否则可以省略。
集成 Commitizen 实现规范提交
上面介绍了angular的提交规范,但是如果需要大家去牢记那些type值,肯定是有压力的,因此我们使用 Commitizen 工具来帮助我们自动生成 commit message 格式,从而实现规范提交
Commitizen 是一个帮助撰写规范 commit message 的工具。它有一个命令行工具 cz-cli。
安装Commitizen
注意:此处需要全局安装
npm install commitizen -g
初始化项目(用 cz-conventional-changelog 适配器来初始化项目:)
npx commitizen init cz-conventional-changelog --save-dev --save-exact
这行命令做了两件事:
- 安装 cz-conventional-changelog 到开发依赖(devDependencies)
- 在
package.json
中增加了config.commitizen
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
}
}
使用Commitizen
以前我们提交代码git commit -m "xxx"
,现在改为 git cz
,然后按照终端操作提示,逐步填入信息,就能自动生成规范的 commit message。
自定义Commitizen配置
从上面的截图可以看到,git cz
终端操作提示都是英文的,如果想改成中文的或者自定义这些配置选项,我们使用 cz-customizable 适配器。
cz-customizable 初始化项目
cz-customizable 初始化项目,之前已经初始化过一次,这次初始化需要加 --force
覆盖。
npx commitizen init cz-customizable --save-dev --save-exact --force
这行命令做了两件事:
- 安装 cz-customizable 到开发依赖(devDependencies)
- 此时
package.json
中的config.commitizen
字段会自动修改为:(如果没有自动修改,需手动修改)
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
}
}
使用 cz-customizable
根目录下创建 .cz-config.js
文件,然后按照官方文档来配置。文档地址:github.com/leoforfree/…
很多时候我们不一定需要不需要写长描述,代码仓库也不需要管理 issue,我们可以将body和footer设置忽略
skipQuestions: ['body', 'footer'],
module.exports = {
// type 类型(定义之后,可通过上下键选择)
types: [
{ value: 'feat', name: 'feat: 新增功能' },
{ value: 'fix', name: 'fix: 修复 bug' },
{ value: 'docs', name: 'docs: 文档变更' },
{ value: 'style', name: 'style: 代码格式(不影响功能,例如空格、分号等格式修正)' },
{ value: 'refactor', name: 'refactor: 代码重构(不包括 bug 修复、功能新增)' },
{ value: 'perf', name: 'perf: 性能优化' },
{ value: 'test', name: 'test: 添加、修改测试用例' },
{ value: 'build', name: 'build: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)' },
{ value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
{ value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' },
{ value: 'revert', name: 'revert: 回滚 commit' }
],
// scope 类型(定义之后,可通过上下键选择)
scopes: [
['components', '组件相关'],
['hooks', 'hook 相关'],
['utils', 'utils 相关'],
['element-ui', '对 element-ui 的调整'],
['styles', '样式相关'],
['deps', '项目依赖'],
['auth', '对 auth 修改'],
['other', '其他修改'],
// 如果选择 custom,后面会让你再输入一个自定义的 scope。也可以不设置此项,把后面的 allowCustomScopes 设置为 true
['custom', '以上都不是?我要自定义']
].map(([value, description]) => {
return {
value,
name: `${value.padEnd(30)} (${description})`
}
}),
// 是否允许自定义填写 scope,在 scope 选择的时候,会有 empty 和 custom 可以选择。
// allowCustomScopes: true,
// allowTicketNumber: false,
// isTicketNumberRequired: false,
// ticketNumberPrefix: 'TICKET-',
// ticketNumberRegExp: '\\d{1,5}',
// 针对每一个 type 去定义对应的 scopes,例如 fix
/*
scopeOverrides: {
fix: [
{ name: 'merge' },
{ name: 'style' },
{ name: 'e2eTest' },
{ name: 'unitTest' }
]
},
*/
// 交互提示信息
messages: {
type: '确保本次提交遵循 Angular 规范!\n选择你要提交的类型:',
scope: '\n选择一个 scope(可选):',
// 选择 scope: custom 时会出下面的提示
customScope: '请输入自定义的 scope:',
subject: '填写简短精炼的变更描述:\n',
body:
'填写更加详细的变更描述(可选)。使用 "|" 换行:\n',
breaking: '列举非兼容性重大的变更(可选):\n',
footer: '列举出所有变更的 ISSUES CLOSED(可选)。 例如: #31, #34:\n',
confirmCommit: '确认提交?'
},
// 设置只有 type 选择了 feat 或 fix,才询问 breaking message
allowBreakingChanges: ['feat', 'fix'],
// 跳过要询问的步骤
skipQuestions: ['body', 'footer'],
// subject 限制长度
subjectLimit: 100,
breaklineChar: '|', // 支持 body 和 footer
// footerPrefix : 'ISSUES CLOSED:'
// askForBreakingChangeFirst : true,
}
此时再去执行git cz
强制代码提交commitlint
安装 @commitlint/config-conventional 和 @commitlint/cli
npm i @commitlint/config-conventional @commitlint/cli -D
配置 commitlint
- 根目录下创建.commitlintrc.js,配置内容如下
module.exports = { extends: ['@commitlint/config-conventional'] }
- 使用 husky 的
commit-msg
hook 触发验证提交信息的命令 - 我们使用 husky 命令在
.husky
目录下创建commit-msg
文件,并在此执行 commit mess
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
验证效果: