本文采用yarn作为包管理器,npm 操作类似。
初始化项目
// 创建一个空的 vue3-ts 项目,
yarn create vite my-vue-app --template vue-ts
// 安装依赖
cd my-vue-app && yarn
// 默认是没有创建git仓库的,这里我们初始化一下
git init
// 创建一个空的 vue3-ts 项目,
yarn create vite my-vue-app --template vue-ts
// 安装依赖
cd my-vue-app && yarn
// 默认是没有创建git仓库的,这里我们初始化一下
git init
这个模板是没有使用配置eslint
和prettier
的,接下来我们依次安装这些依赖。
集成eslint
首先我们安装eslint
yarn add eslint -D
接下来初始化eslint
:
npx eslint --init
依次选择这些选项:
到最后一步时会弹一个这个提示,问是否立即用npm安装这个三个依赖,这里我们选否,并且手动拷贝出来用yarn安装。
yarn add eslint-plugin-vue@latest @typescript-eslint/eslint-plugin@latest
@typescript-eslint/parser@latest -D
到这一步,我们就已经安装了相关的依赖了,并且得到一个已配置好的.eslintrc.json
文件:
{
// 设置我们的运行环境为浏览器 + es2021 + node ,否则eslint在遇到 Promise,window等全局对象时会报错
"env": {
"browser": true,
"es2021": true,
"node": true
},
// 继承eslint推荐的规则集,vue基本的规则集,typescript的规则集
"extends": [
"eslint:recommended",
"plugin:vue/essential",
"plugin:@typescript-eslint/recommended"
],
// 支持ts的最新语法
"parserOptions": {
"ecmaVersion": 13,
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
// 添加vue和@typescript-eslint插件,增强eslint的能力
"plugins": [
"vue",
"@typescript-eslint"
],
"rules": {
}
}
然后我们为package.json
文件增加一个lint
命令
{
"scripts":{
// lint当前项目中的文件并且开启自动修复
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
}
}
一切进行得非常顺利,然而当我们运行lint命令时,会发现不是我们想要的结果:
命令行在解析vue
文件会报parsing error
。这是因为,默认eslint
不会解析vue文件,所以我们需要一个额外的解析器来帮我们解析vue文件。
这一步本来是在我们继承plugin:vue/essential
的时候,默认为我们配置了的
但是我们后续又extend
了"plugin:@typescript-eslint/recommended"
,它又继承来自./node_modules/@typescript-eslint/eslint-plugin/dist/configs/base.js
而我们在配置文件中的extends顺序是:
{
"extends": [
"eslint:recommended",
"plugin:vue/essential",
"plugin:@typescript-eslint/recommended"
],
}
所以vue-eslint-parser
被@typescript-eslint/parser
覆盖了。这里我们只需要将外部的parser
改为vue-eslint-parser
,并且在parserOptions
中添加一个parser:@typescript-eslint/parser
属性即可,而这一步我们之前的配置文件里面已经有做了。
{
...
// 新增,解析vue文件
"parser":"vue-eslint-parser",
"parserOptions": {
"ecmaVersion": "latest",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
...
}
两个parser
的区别在于,外面的parser
用来解析vue
文件,使得eslint
能解析<template>
标签中的内容,而parserOptions
中的parser
,即@typescript-eslint/parser
用来解析vue文件中<script>
标签中的代码。
接下来我们继续运行 yarn run lint
,会发现又报错了:
这里一共报两个问题,
<template>
节点要求有且只有一个根节点- 找不到
defineProps
的定义
我们知道,这两个特性都是vue3引入的,问题可能出在我们的配置不支持vue3项目,翻阅./node_modules/eslint-plugin-vue
目录的相关配置,便可发现问题所在,eslint-plugin-vue
提供了几个预设的配置集。
没有vue3-
前缀的规则集对应vue2项目,vue3-
开头的对应vue3项目。而我们默认使用的是 vue/essential
这个规则集,由于我们是vue3项目,所以应该使用vue3的规则集,这里使用vue3-recommended
{
"extends": [
"eslint:recommended",
-- "plugin:vue/essential",
++ "plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended"
],
}
然后再运行,yarn run lint
,发现还是会报错。
因为defineProps是一个全局的预编译宏,eslint
不知其定义在哪里,所以需要在global
选项中将其标注出来,然而我阅读了eslint-plugin-vue
这个文件后,发现它已经预设了。
我们只需要在env中开启这个环境变量即可:
{
"env": {
"browser": true,
"es2021": true,
"node": true,
// 开启setup语法糖环境
++ "vue/setup-compiler-macros":true
},
}
然后我们再运行yarn run lint
,oh 谢天谢地,终于不报错了。
添加vscode-eslint 插件
就目前而言,我们能在命令行中使用eslint了,然而写一行代码就去运行下检测脚本实在太麻烦,好在我们可以结合vscode-eslint
插件使用。
在vscode
中安装好vscode-eslint
插件,它便会在我们写代码的时候对我们的脚本进行lint,我们就没必要再运行yarn run lint
了。同时,我们可以新建一个.vscode/settings.json
文件,为这个本项目开启自动修复
{
"editor.codeActionsOnSave": {
"source.fixAll": true
}
}
这样一来,当你按下ctrl + s
保存的时候,eslint
便会智能地为你修复一些代码错误了。
集成 prettier
相比 eslint
而言 prettier
就会要温和一些了。 prettier 并没有提供太多的配置选项给我们选择,所以我们在网上随便找一份配置就行。
yarn add prettier -D
然后再项目根目录添加一份配置文件
// .prettierrc.js
module.exports = {
printWidth: 80, //单行长度
tabWidth: 2, //缩进长度
useTabs: false, //使用空格代替tab缩进
semi: true, //句末使用分号
singleQuote: true, //使用单引号
}
这是我的配置文件,如果需要更多的配置方法,可以参考官方的配置文档。
然后再package.json中添加一个脚本
{
"scripts":{
"format": "prettier --write ./**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}"
}
}
当运行这个命令时,就会将我们项目中的文件都格式化一次。
一般而言,我们还需要集成 vscode-prettier
这个插件来完成自动保存格式化,在插件市场安装好了以后,在我们的.vscode/settings.json
中添加如下规则
{
"editor.formatOnSave": true, // 开启自动保存
"editor.defaultFormatter": "esbenp.prettier-vscode", // 默认格式化工具选择prettier
}
这样一来,当我们在vscode写代码的时候,便会自动格式化了。
解决 eslint 和 prettier 的冲突
理想状态下,到这一步我们写代码的时候,eslint
和 prettier
会相互协作,既美化我们的代码,也修复我们质量不过关的代码。然而现实总是不那么完美,我们会发现某些时候,eslint
提示错误,我们修改了以后,屏幕会闪一下然后又恢复到报错状态,自动修复失效了。
这是因为eslint
有一部分负责美化代码的规则和 prettier
的规则冲突了,这里可以参考我的另外一篇博客《解决Eslint 和 Prettier 之间的冲突》,这里我们只给出方案。 用 eslint-config-prettier
提供的规则集来覆盖掉eslint
冲突的规则,并用eslint-plugin-prettier
来使eslint
使用prettier
的规则来美化代码。
yarn add eslint-config-prettier eslint-plugin-prettier -D
然后在 .eslintrc.json
中extends
的最后添加一个配置:
"extends": [
"eslint:recommended",
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended" // 新增,必须放在最后面
],
然后我们重启一下vscode,就会发现冲突消失了,我们的自动修复和自动格式化也能相互协作了。
配置 husky + lint-staged
理论上,到上一步我们已经能使得我们的项目获得不错的开发规范约束了。然而仍然有可以改进的地方:
- 如果是在项目中途才接入
eslint + prettier
,如果对原来的代码使用yarn run lint
或者yarn run format
势必会带来大范围地改动,甚至会造成冲突。 - 对于一些不使用
vscode
编辑器,或者没有安装prettier
和eslint
插件的用户而言,他们不能享受到插件带来的协助,而他们的代码自然大概率是不符合规范的,不该被提交到代码库。
基于上述的顾虑,社区提供了 husky + lint-staged
的渐进式方案。 lint-staged
是一个只检测git
暂存区的lint
工具,husky
是一个用来给我们的项目添加git hook
的工具,git hook
是进行git操作会触发的脚本,例如:提交的时候会触发pre-commit
钩子,输入提交信息会触发commit-msg
钩子。 我们用husky
安装pre-commit
钩子,我们就可以在进行git commit
操作的时候,运行我们的脚本来检测待提交的代码是否规范,便可以只对暂存区的文件进行检查。
首先安装依赖
yarn add husky lint-staged -D
添加一个在package.json
中添加一条preinstall
脚本
{
"script":{
"prepare": "husky install"
}
}
prepare
脚本会在 yarn install
之后自动运行,这样依赖你的小伙伴clone
了你的项目之后会自动安装husky
,这里由于我们已经运行过 yarn install
了,所以我们需要手动运行一次yarn run prepare
,然后我们就会得到一个目录.husky
。
接下来我们为我们git仓库添加一个pre-commit
钩子,运行
npx husky add .husky/pre-commit "npx --no-install lint-staged"
这回在我们的.husky目录下生成一个pre-commit
的脚本
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install lint-staged
接下来我们配置lint-staged
,在package.json
中添加下面的配置信息。
{
"lint-staged": {
"*.{js,vue,ts,jsx,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.{html,css,less,scss,md}": [
"prettier --write"
]
}
}
这样之后,我们后续提交到暂存区的代码也就会被eslint+prettier
格式化和检查,进一步保证我们的代码规范。
配置文件总览
// package.json
{
"name": "my-vue-app",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
"format": "prettier --write ./**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}",
"prepare": "husky install"
},
"dependencies": {
"vue": "^3.2.25"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
"@vitejs/plugin-vue": "^2.0.0",
"eslint": "^8.4.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.2.0",
"husky": "^7.0.4",
"lint-staged": "^12.1.3",
"prettier": "^2.5.1",
"typescript": "^4.4.4",
"vite": "^2.7.2",
"vue-tsc": "^0.29.8"
},
"lint-staged": {
"*.{js,vue,ts,jsx,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.{html,css,less,scss,md}": [
"prettier --write"
]
}
}
// .eslintrc.json
{
"env": {
"browser": true,
"es2021": true,
"node": true,
"vue/setup-compiler-macros": true
},
"extends": [
"eslint:recommended",
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "vue-eslint-parser",
"parserOptions": {
"ecmaVersion": "latest",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": ["vue", "@typescript-eslint"],
"rules": {}
}
// .prettierrc.js
module.exports = {
printWidth: 80, //单行长度
tabWidth: 2, //缩进长度
useTabs: false, //使用空格代替tab缩进
semi: true, //句末使用分号
singleQuote: true, //使用单引号
};
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll": true
}
}
// .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install lint-staged
总结
// package.json
{
"name": "my-vue-app",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
"format": "prettier --write ./**/*.{vue,ts,tsx,js,jsx,css,less,scss,json,md}",
"prepare": "husky install"
},
"dependencies": {
"vue": "^3.2.25"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
"@vitejs/plugin-vue": "^2.0.0",
"eslint": "^8.4.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.2.0",
"husky": "^7.0.4",
"lint-staged": "^12.1.3",
"prettier": "^2.5.1",
"typescript": "^4.4.4",
"vite": "^2.7.2",
"vue-tsc": "^0.29.8"
},
"lint-staged": {
"*.{js,vue,ts,jsx,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.{html,css,less,scss,md}": [
"prettier --write"
]
}
}
// .eslintrc.json
{
"env": {
"browser": true,
"es2021": true,
"node": true,
"vue/setup-compiler-macros": true
},
"extends": [
"eslint:recommended",
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "vue-eslint-parser",
"parserOptions": {
"ecmaVersion": "latest",
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"plugins": ["vue", "@typescript-eslint"],
"rules": {}
}
// .prettierrc.js
module.exports = {
printWidth: 80, //单行长度
tabWidth: 2, //缩进长度
useTabs: false, //使用空格代替tab缩进
semi: true, //句末使用分号
singleQuote: true, //使用单引号
};
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll": true
}
}
// .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install lint-staged
本文从实战出发,为一个 vite-vue3-ts
项目添加了eslint + prettier + husky + lint-staged
项目规范,希望大家能从中学到知识。代码已经上传到github
上,点击这里即可查看。
如果你觉得本文对你有些许帮助的话,记得点个赞哦